Skip to content

signOut server action silently skips the WorkOS end-session redirect when withAuth() resolves no session (cookie fallback unreachable) #474

Description

@BtotheT

Summary

signOut() (dist/esm/auth.js) resolves the session id via withAuth() inside a try/catch, with a cookie-decode fallback in the catch. But withAuth() returns a quiet { user: null } (no throw) when getSessionFromHeader() finds the middleware marker header present but no session header — so sessionId stays undefined, the catch-side cookie fallback is unreachable, and the finally deletes the cookie and does the LOCAL redirect only. The end-session redirect through userManagement.getLogoutUrl never happens.

Observed impact (production-like deploy, authkit-nextjs ^4.x, Next 15.5, next start behind nginx)

  • Network capture on logout click: zero requests to api.workos.com — the sessions/logout hop never occurs.
  • wos-session cookie is deleted, so the app looks signed out.
  • The IdP session at the AuthKit hosted-UI domain (*.authkit.app) survives; the next sign-in silently completes via the hosted domain's refresh-token endpoint with no credential prompt — the user cannot actually log out.

Context that may matter: middleware integrates via authkit(request) + handleAuthkitProxy() (the documented proxy pattern), and the sign-out call reaches the action through the client useAuth().signOuthandleSignOutAction. In this setup the action evidently sees the middleware marker but not the session header.

Suggested fix

Make the cookie fallback reachable on the quiet-null path, e.g.:

let sessionId;
try {
  ({ sessionId } = await withAuth());
} catch (error) { /* existing fallback */ }
if (!sessionId) {
  const session = await getSessionFromCookie();
  if (session?.accessToken) sessionId = decodeJwt(session.accessToken).sid;
}

i.e. treat "withAuth resolved but produced no sessionId" the same as the throw path — the cookie is right there and carries the sid.

Workaround we shipped

A route handler that unseals the cookie directly (iron-session), extracts sid, and redirects through userManagement.getLogoutUrl — happy to link it if useful. We'd much rather delete it when the fallback becomes reachable upstream.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions