-
Notifications
You must be signed in to change notification settings - Fork 731
Description
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:
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
// Current behavior
router.get('/logout', async (req, res) => {
await provider.handleLogout(req, res);
req.session.destroy(() => res.redirect(admin.options.rootPath + '/login'));
});// 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
handleLogoutreturnsundefined. - Minimal change: no breaking API changes or new interfaces.
Alternatives
No response
Additional Context
No response