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

  1. Revoke tokens - Logout'ta token'ları iptal et
  2. Clear all sessions - Server-side session'ı yok et
  3. Clear cookies - Frontend cookie'leri temizle
  4. Use POST - Logout endpoint'i POST olmalı (CSRF)
  5. Confirm logout - Önemli işlemler varsa onay iste

❌ Don't

  1. GET ile logout - CSRF riski
  2. Token'ları bırak - Revoke etmezsen hala geçerli
  3. Client-side only - Backend'de de session temizle
  4. 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