Summary
A critical session mismatch occurred where the application-level session (NextAuth) was terminated, but the Identity Provider (IdP) session (Authentik) remained active. This resulted in a “Zombie Session” state: users appeared logged out of the application, but any attempt to re-authenticate immediately re-established the session without user interaction. This creates a severe security risk in shared terminal environments.
Root Cause
The failure stems from a misunderstanding of Distributed Session Management in OIDC flows.
- Local vs. Remote Sessions:
signOut()only destroys the local application cookie. It has no authority over the cookies set byauth.example.com. - OIDC End-Session Failure: The implementation attempted an OIDC Logout flow, but the IdP (Authentik) failed to respect the
post_logout_redirect_uriparameter. - IdP Configuration Mismatch: Authentik’s “Default Invalidation Flow” is being triggered because the Redirect URI provided in the logout request was not explicitly whitelisted in the Authentik Application settings, or the
id_token_hintwas missing/invalid, causing the IdP to treat the request as an unauthenticated logout attempt.
Why This Happens in Real Systems
In modern microservices and SSO architectures, authentication is a two-step handshake:
- The App Session: A short-lived cookie used by your Next.js server to identify the user.
- The IdP Session: A long-lived cookie held by the Identity Provider (Authentik, Okta, Auth0) that allows for Single Sign-On (SSO).
When you only clear the local session, you are essentially closing the door to your house while leaving the master key in the lock. The next time the user “knocks” (tries to log in), the IdP sees their valid master key and immediately lets them back in without asking for credentials.
Real-World Impact
- Account Takeover Risk: In public or shared computing environments (libraries, kiosks), the next user gains immediate access to the previous user’s account.
- Broken Security UX: Users believe they are secure because they “logged out,” leading to a false sense of privacy.
- Compliance Violations: Failure to implement complete session termination can violate SOC2 or GDPR requirements regarding session management and access control.
Example or Code (if necessary and relevant)
// The INCORRECT way: Only clears local session
await signOut({ redirect: false });
router.push('/login');
// The CORRECT way: Orchestrating both local and remote termination
export async function handleGlobalLogout(idToken: string) {
// 1. Clear the local NextAuth session
await signOut({ redirect: false });
// 2. Construct the OIDC End Session URL
const idpLogoutUrl = new URL("https://auth.example.com/application/o/my-app/end-session/");
// id_token_hint is MANDATORY for many IdPs to identify which session to kill
idpLogoutUrl.searchParams.set("id_token_hint", idToken);
// This MUST be pre-registered in the Authentik 'Redirect URIs' list
idpLogoutUrl.searchParams.set("post_logout_redirect_uri", "https://myapp.example.com/login");
// 3. Perform the hard redirect to the IdP
window.location.href = idpLogoutUrl.toString();
}
How Senior Engineers Fix It
- Verify IdP Whitelisting: Ensure that the
post_logout_redirect_uriis explicitly added to the Allowed Redirect URIs in the Authentik provider configuration. If it isn’t an exact match, the IdP will intercept the flow with an error/confirmation screen. - Implement
id_token_hint: Never attempt an OIDC logout without passing theid_token. Without it, the IdP doesn’t know which specific user session is being terminated and defaults to a generic, interactive logout UI. - Session Synchronization: Ensure the
id_tokenis being persisted in the NextAuthjwtorsessioncallback so it is available at the moment of logout. - End-to-End Testing: Validate the flow by logging in, closing the browser tab, opening a new tab, and ensuring the user is actually prompted for credentials.
Why Juniors Miss It
- Local-First Mindset: Juniors often assume that
signOut()is a global command that handles everything. They focus on the Application Code and ignore the Infrastructure/IdP Configuration. - Ignoring the Protocol: They treat OIDC as a “black box” rather than a strict protocol with specific requirements like
id_token_hintand strict redirect URI matching. - Testing Shallowly: They test logout by checking if their local
useSession()returnsnull, which passes even if the IdP session is still perfectly intact.