Logout
Atlantic ID'den güvenli çıkış yapma rehberi.
Logout Türleri
1. Local Logout
Sadece kendi uygulamanızdan çıkış:
app.post('/logout', (req, res) => {
req.session.destroy();
res.redirect('/');
});
Sonuç: Kullanıcı sizin uygulamanızdan çıkar, ancak Atlantic ID session'u devam eder.
2. Single Sign-Out (SSO Logout)
Atlantic ID'den de çıkış:
app.post('/logout', (req, res) => {
const idToken = req.session.idToken;
// Local session temizle
req.session.destroy();
// Atlantic ID logout'a yönlendir
const logoutUrl = new URL('https://id.codeatlantis.com/oauth/logout');
logoutUrl.searchParams.set('id_token_hint', idToken);
logoutUrl.searchParams.set('post_logout_redirect_uri', 'https://myapp.com/goodbye');
res.redirect(logoutUrl.toString());
});
Sonuç: Kullanıcı hem sizin uygulamanızdan hem Atlantic ID'den çıkar.
Front-Channel Logout
Endpoint
GET https://id.codeatlantis.com/oauth/logout
Parametreler
| Param | Tip | Zorunlu | Açıklama |
|---|---|---|---|
id_token_hint |
string | 📝 | ID token (önerilen) |
post_logout_redirect_uri |
string | ❌ | Logout sonrası dönüş URL'i |
state |
string | ❌ | State to relay back |
Örnek
const logoutUrl = new URL('https://id.codeatlantis.com/oauth/logout');
logoutUrl.searchParams.set('id_token_hint', storedIdToken);
logoutUrl.searchParams.set('post_logout_redirect_uri', 'https://myapp.com');
window.location.href = logoutUrl.toString();
Flow:
1. User clicks logout
2. App redirects to Atlantic ID logout
3. Atlantic ID clears session
4. Atlantic ID redirects back to post_logout_redirect_uri
Back-Channel Logout (Token Revocation)
Access ve refresh token'ları iptal etme:
Endpoint
POST https://id.codeatlantis.com/oauth/revoke
Request
POST /oauth/revoke HTTP/1.1
Host: id.codeatlantis.com
Content-Type: application/x-www-form-urlencoded
Authorization: Basic Y2xpX2FiYzEyMzpzZWNfZGVmNDU2
token=RT_xxxxxxxxxxxxxxxxxxxxxxxx&
token_type_hint=refresh_token
JavaScript Example
async function revokeToken(token) {
const response = await fetch('https://id.codeatlantis.com/oauth/revoke', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': `Basic ${btoa(clientId + ':' + clientSecret)}`
},
body: new URLSearchParams({
token: token,
token_type_hint: 'refresh_token'
})
});
// 200 OK regardless of token validity
return response.ok;
}
Tam Logout Flow
Backend
app.post('/logout', async (req, res) => {
try {
// 1. Revoke refresh token
if (req.session.refreshToken) {
await revokeToken(req.session.refreshToken);
}
// 2. Store ID token for SSO logout
const idToken = req.session.idToken;
// 3. Destroy local session
req.session.destroy((err) => {
if (err) console.error('Session destroy error:', err);
// 4. Clear cookies
res.clearCookie('connect.sid');
// 5. Redirect to Atlantic ID logout
const logoutUrl = new URL('https://id.codeatlantis.com/oauth/logout');
logoutUrl.searchParams.set('id_token_hint', idToken);
logoutUrl.searchParams.set('post_logout_redirect_uri', 'https://myapp.com');
res.redirect(logoutUrl.toString());
});
} catch (error) {
console.error('Logout error:', error);
res.redirect('/');
}
});
Frontend
async function logout() {
try {
// Call backend logout
await fetch('/api/logout', { method: 'POST' });
// Clear local storage (if any)
sessionStorage.clear();
// Redirect will be handled by backend
} catch (error) {
console.error('Logout failed:', error);
// Force redirect anyway
window.location.href = '/';
}
}
Multi-Application Logout
Aynı Atlantic ID ile birden fazla app'e login olmuş kullanıcı:
User logged in:
├── App A (myapp.com)
├── App B (anotherapp.com)
└── App C (thirdapp.com)
User logs out from App A:
├── Atlantic ID session cleared
├── App A: Logged out ✅
├── App B: Still logged in (local session)
└── App C: Still logged in (local session)
Next time user visits App B or C:
→ Atlantic ID session yok
→ Re-authentication required
Not: Atlantic ID logout yapmak, her app'in local session'ını otomatik temizlemez. User her app'e gittiğinde tekrar login gerekir.
Logout Confirmation
<!-- Logout confirmation modal -->
<div id="logout-modal">
<h2>Çıkış Yapmak İstediğinize Emin Misiniz?</h2>
<p>Tüm oturumlarınız sonlandırılacak.</p>
<button onclick="confirmLogout()">Evet, Çıkış Yap</button>
<button onclick="cancelLogout()">İptal</button>
</div>
<script>
function confirmLogout() {
fetch('/api/logout', { method: 'POST' })
.then(() => window.location.href = '/');
}
</script>
Automatic Logout
Session Timeout
const TIMEOUT = 30 * 60 * 1000; // 30 dakika
let timeoutId;
function resetTimeout() {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
alert('Oturum zaman aşımına uğradı.');
logout();
}, TIMEOUT);
}
// User activity olduğunda reset
['click', 'keypress', 'scroll', 'mousemove'].forEach(event => {
document.addEventListener(event, resetTimeout, { passive: true });
});
resetTimeout();
Token Expiration
// Access token expired → Auto refresh
// Refresh token expired → Force logout
async function checkTokenExpiration() {
const expiresAt = sessionStorage.getItem('token_expires_at');
if (Date.now() >= expiresAt) {
try {
await refreshToken();
} catch (error) {
// Refresh failed → logout
logout();
}
}
}
setInterval(checkTokenExpiration, 60000); // Her dakika kontrol
Post-Logout Page
<!DOCTYPE html>
<html>
<head>
<title>Çıkış Yapıldı</title>
</head>
<body>
<div class="logout-message">
<h1>Güvenli Çıkış Yapıldı</h1>
<p>Atlantic ID oturumunuz sonlandırıldı.</p>
<a href="/">Ana Sayfaya Dön</a>
</div>
</body>
</html>
Security Considerations
✅ Do
- Revoke tokens - Logout'ta token'ları iptal et
- Clear all sessions - Server-side session'ı yok et
- Clear cookies - Frontend cookie'leri temizle
- Use POST - Logout endpoint'i POST olmalı (CSRF)
- Confirm logout - Önemli işlemler varsa onay iste
❌ Don't
- GET ile logout - CSRF riski
- Token'ları bırak - Revoke etmezsen hala geçerli
- Client-side only - Backend'de de session temizle
- Silent logout - User'a bilgi ver
Testing
describe('Logout', () => {
it('should clear session', async () => {
await request(app).post('/logout').expect(302);
// Session temizlendi mi?
const session = await getSession(sessionId);
expect(session).toBeNull();
});
it('should revoke tokens', async () => {
await logout(refreshToken);
// Token revoke edildi mi?
const tokenValid = await validateToken(refreshToken);
expect(tokenValid).toBe(false);
});
});
İlgili: Session Management, Token Refresh, Security