Logout & Session Propagation
UniAuth supports three complementary logout mechanisms from OIDC 1.0. The goal: when a user signs out of your app, the session is revoked at UniAuth too, and other apps the user signed into can be notified.
Common mistake: clearing your own session cookie does not log the user out of UniAuth. They can re-authenticate with a single click. Always use end_session_endpoint for real logout, and configure a back-channel logout URL so UniAuth can notify you when the user signs out elsewhere.
1. RP-Initiated Logout
When the user clicks “sign out” in your app, redirect them to the end_session_endpoint. UniAuth will revoke their session and redirect back to your configured post-logout URL.
// Build the logout URL from discovery
const params = new URLSearchParams({
id_token_hint: userIdToken, // so UniAuth knows who to log out
post_logout_redirect_uri: 'https://yourapp.com/',
state: 'xyz123', // optional, for CSRF
})
window.location.href =
`https://uniauth.id/api/oauth/end-session?${params}`With our SDK, this is a single call:
await auth.logout({ postLogoutRedirectUri: 'https://yourapp.com/' })
// SDK handles: revoke refresh token → redirect to end_session_endpoint2. Back-Channel Logout
When the user logs out of UniAuth (from any app, or the UniAuth dashboard), UniAuth sends a signed logout token via HTTP POST to every registered backchannel_logout_uri. Your app invalidates the local session server-side. No browser redirects involved.
Register your back-channel URL when creating the OAuth client in the Developer Console.
Verifying the Logout Token
UniAuth sends a logout token as application/x-www-form-urlencoded with logout_token=.... It's an RS256-signed JWT:
// Node.js example using jose
import { jwtVerify, createRemoteJWKSet } from 'jose'
const JWKS = createRemoteJWKSet(
new URL('https://uniauth.id/.well-known/jwks.json')
)
app.post('/logout-webhook', express.urlencoded(), async (req, res) => {
const token = req.body.logout_token
try {
const { payload } = await jwtVerify(token, JWKS, {
issuer: 'https://uniauth.id',
audience: process.env.CLIENT_ID,
})
// Required claim checks per OIDC Back-Channel Logout 1.0
if (!payload.sid && !payload.sub) {
return res.status(400).end()
}
if (payload.events?.['http://schemas.openid.net/event/backchannel-logout'] == null) {
return res.status(400).end()
}
if (payload.nonce) {
// Logout tokens MUST NOT contain a nonce
return res.status(400).end()
}
// Invalidate all your local sessions for this user / sid
await invalidateSession({ sub: payload.sub, sid: payload.sid })
res.status(200).end()
} catch (err) {
res.status(400).end()
}
})3. Front-Channel Logout
An alternative to back-channel: UniAuth returns iframe URLs to load during logout. Each iframe loads your registered frontchannel_logout_uri with ?iss=...&sid=.... Your app clears client-side state (cookies, localStorage) server-side using the sid.
Use back-channel when possible — front-channel requires third-party cookies, which most browsers now block.
Which Should You Use?
| Mechanism | When It Fires | Requires Browser? | Recommended? |
|---|---|---|---|
| end_session | User clicks logout in your app | Yes (redirect) | ✅ Always |
| back-channel | Logout from any app or UniAuth dashboard | No (server-to-server) | ✅ If you have a backend |
| front-channel | Same as back-channel | Yes (iframe) | ⚠️ Third-party cookies often blocked |