Obexal Docs

Docs/Authentication/Sessions and logout

Sessions and logout

How Obexal sessions work (opaque, server-side, revocable) and every way to end them: self-service, RP-initiated logout and OIDC Back-Channel Logout.

An Obexal session is not a JWT sitting in the browser: it is an opaque, server-side record that can be revoked at any moment, with immediate effect. This page explains the session model, the self-service controls users get, and the two logout mechanisms applications can rely on.

Note

Examples use accounts.obexal.com, the default domain. With a custom domain, replace it accordingly.

How sessions work

Signing in sets a session cookie (obexal_session by default): an HttpOnly, Secure cookie containing a random 32-byte opaque token, with SameSite=Lax. The cookie carries no data at all. Server-side, only the SHA-256 hash of the token is stored (Redis, mirrored in PostgreSQL), so a database leak exposes no usable session.

Because the state lives on the server, revocation is instantaneous: there is no self-contained token to wait out. The default session lifetime is 24 hours, configurable on self-hosted deployments.

Some security events revoke sessions automatically: a password reset and a confirmed email change revoke all of the user's sessions; an authenticated password change revokes all sessions except the current one.

Self-service: list and revoke your sessions

Users can see and terminate their own sessions. These endpoints require a valid session; the mutating ones also require the CSRF header (X-CSRF-Token), like the rest of /v1.

curl -sS -b cookies.txt https://accounts.obexal.com/v1/auth/sessions
{
  "sessions": [
    {
      "id": "c9a1f4e2",
      "device": "Firefox on Linux",
      "ip": "203.0.113.7",
      "createdAt": "2026-07-01T08:12:00Z",
      "lastSeenAt": "2026-07-02T09:40:00Z",
      "current": true
    }
  ]
}

Revoke one session, or everything except the current one:

curl -sS -b cookies.txt -X DELETE "https://accounts.obexal.com/v1/auth/sessions/<id>" \
  -H "X-CSRF-Token: $CSRF"
# 204 (revoking the current session also clears the cookie)

curl -sS -b cookies.txt -X POST https://accounts.obexal.com/v1/auth/sessions/revoke-others \
  -H "X-CSRF-Token: $CSRF"
# 200 -> {"revoked": 3}

GET /v1/auth/login-history completes the picture with the user's recent sign-ins, successful and failed.

Signing out of Obexal

POST /v1/auth/logout revokes the current session, clears the cookie and returns 204. It is idempotent: calling it without a valid session also returns 204. After revocation, Obexal asynchronously notifies the user's applications through Back-Channel Logout (see below).

RP-initiated logout

GET /oauth/logout is the end_session_endpoint advertised in the discovery document. An application (RP) redirects the user's browser there to end the Obexal session:

https://accounts.obexal.com/oauth/logout?client_id=app_a1b2c3&post_logout_redirect_uri=https%3A%2F%2Fapp.example.eu%2Fcallback&state=xyz

The session is revoked and the cookie cleared, then the browser is redirected. The post_logout_redirect_uri is only honored if it exactly matches one of the client's registered redirect URIs (allowlist, anti open-redirect); state, if present, is echoed on that redirect. Otherwise the user lands on the hosted sign-in page. The endpoint does not use id_token_hint: identify the client explicitly with client_id.

Back-Channel Logout (OIDC)

For real single logout, register a backchannelLogoutUri on your application (field of POST /v1/applications, or PATCH later). When the user signs out, Obexal POSTs a signed logout token (form-encoded, field logout_token) directly to that URI, server to server, for every application the user has a grant with. Delivery is best-effort, through an SSRF-safe, time-bounded HTTP client.

The logout token is a JWT signed RS256 with header typ: logout+jwt:

{
  "iss": "https://accounts.obexal.com",
  "sub": "8f2c1e9a-4b7d-4c2e-9f1a-3d5e7b9c0a12",
  "aud": "app_a1b2c3",
  "iat": 1751449400,
  "jti": "q4Zr8w...",
  "events": { "http://schemas.openid.net/event/backchannel-logout": {} }
}

On reception, your application must validate the signature against the JWKS, check iss, aud and iat, verify the events claim, enforce jti single use, then terminate its own local sessions for sub and answer 200.

The discovery document advertises backchannel_logout_supported: true and backchannel_logout_session_supported: false: logout is addressed by sub, so your application should end all local sessions of that user; there is no sid claim.

Limits

  • No front-channel logout (the iframe-based mechanism): Back-Channel Logout is the supported single-logout path.
  • Logout tokens identify the user (sub), not an individual session (sid).
  • Back-channel delivery is best-effort: an application that is unreachable at that moment is not retried. Keep your local sessions short and validate access tokens properly; see Validate tokens.