#1791·adminjs

[Feature]: Use Redirect URL Returned by `handleLogout` in BaseAuthProvider

Author: gugupyCreated Oct 18, 2025Updated Oct 31, 2025

Description

Problem

Currently, all AdminJS authentication adapters (@adminjs/express, @adminjs/fastify, @adminjs/nestjs) handle logout by destroying the local session and redirecting to the login URL, for example:

typescript
router.get('/logout', (req, res) => {
  req.session.destroy(() => res.redirect(admin.options.rootPath + '/login'));
});

This works for simple local authentication but does not support OAuth/OIDC logout flows, such as with:

  • Keycloak
  • Auth0
  • Azure AD
  • Google Workspace

In these cases, AdminJS only clears the local session but never calls the provider’s logout endpoint — so the user remains authenticated at the provider level. When they revisit the login page, they are automatically re-logged in (silent login).

Why This Matters

Each OAuth provider has its own logout URL (e.g., Keycloak’s protocol/openid-connect/logout), and these need to be called explicitly.

Because AdminJS plugins manage logout internally and redirect immediately, there’s no clean way to integrate provider-specific logout behavior.

Suggested Solution

When the configured BaseAuthProvider implements handleLogout, and that function returns a redirect URL, the adapters should redirect to that URL instead of hardcoding the login redirect. This is help

typescript
// Current behavior
router.get('/logout', async (req, res) => {
  await provider.handleLogout(req, res);
  req.session.destroy(() => res.redirect(admin.options.rootPath + '/login'));
});
typescript
// Proposed behavior
router.get('/logout', async (req, res) => {
  const redirectUrl = await provider.handleLogout?.(req, res);

  // Always destroy the session
  if (req.session) {
    await new Promise(resolve => req.session.destroy(resolve));
  }

  // If handleLogout returned a URL, redirect there
  if (redirectUrl) {
    return res.redirect(redirectUrl);
  }

  // Otherwise, fallback to AdminJS login path
  return res.redirect(admin.options.rootPath + '/login');
});

Benefits

  • Proper OAuth logout support: enables redirecting to provider logout endpoints.
  • Backward compatible: existing providers continue to work if handleLogout returns undefined.
  • Minimal change: no breaking API changes or new interfaces.

Alternatives

No response

Additional Context

No response

Source: SoftwareBrothers/adminjs