Sessions
The package runs on Laravel’s session, unchanged. It ships no session driver, no session store
and no session handler, and it never swaps the one your application configured. What it adds is a
second, different thing: oidc_sessions, the SSO session the OIDC protocol needs.
The two sit side by side. Confusing them is easy, because both are called “session” and both end at logout.
| Laravel’s session | oidc_sessions |
|
|---|---|---|
| What it is | Browser ↔ server state, behind a cookie and SESSION_DRIVER |
The OIDC SSO session |
| Identified by | Laravel’s session id | id, a UUID, published as the sid claim |
| Holds | Login state, CSRF token, flash data, the package’s own keys below | The user, the realm, the participating clients, the absolute expiry |
| Lifetime | config('session.lifetime') — idle, extended by use |
oidc.session.absolute_lifetime — absolute, from login, never extended |
| Ends when | The browser is logged out, or it goes idle | It is revoked at logout, or reaches its absolute expiry |
| Visible as | Nothing in the protocol | The sid claim in id tokens and logout tokens |
What links them
Section titled “What links them”Three separate mappings exist, each for a different job.
oidc.sid in Laravel’s session. On the Login event for the identity guard, StartOidcSession
inserts the oidc_sessions row and writes its id into Laravel’s session. This is what the
authorize endpoint reads to stamp session_id onto the authentication context, and what the logout listener
reads to know which SSO session to revoke.
browser_session_id on oidc_sessions. The same listener records the browser session id the login ended
in. OidcSessionRepository::findByBrowserSession() looks a session up by it, so an account page
listing a user’s browser sessions can end the OIDC session behind one without decoding the session
payload — which would break under an encrypted or differently serialized session. See
Logout.
The relying party’s cache map. A relying party is usually a different application that cannot see
the provider’s tables at all. The client package therefore keeps its own sid → session id map in
the cache (BackchannelLogoutStore) so an incoming logout token can find and destroy the local
session — see Back-channel logout.
What the package keeps in Laravel’s session
Section titled “What the package keeps in Laravel’s session”| Key | Holds |
|---|---|
oidc.sid |
The oidc_sessions.id of this browser’s SSO session |
oidc.auth_time |
When the user authenticated, for auth_time and max_age |
oidc.amr |
The authentication methods used, which acr is derived from |
oidc.id_token_claims, oidc.access_token_claims |
Claims buffered by the post-login pipeline |
oidc.requested_acr_values |
The acr_values the authorize request asked for |
oidc.requested_actions |
Pending required actions |
oidc.session_token |
The session root token — a full access token |
oidc.authorize_request, oidc.consent_token |
The stashed authorize request and its consent token |
oidc.social.pending |
Whether a social redirect is a login or an account link |
oidc.webauthn.enrollment, login.* |
In-flight passkey enrollment and MFA challenge state |
AuthSessionState::forget() clears the login-derived keys after a login completes but deliberately
keeps oidc.sid and oidc.auth_time: they describe the SSO session, not one login attempt.
Lifetimes
Section titled “Lifetimes”The two caps are independent and enforce different things.
Laravel’s session.lifetime governs the browser: when it lapses, the cookie’s session is gone and
the user is anonymous, whatever oidc_sessions says.
oidc.session.absolute_lifetime (30 days by default) is stamped onto oidc_sessions.expires_at at
login and never extended. It gates two things: a refresh token whose authentication context names an
inactive session is denied with session_ended, and the session becomes eligible for back-channel
logout notification once it is past. It is also copied onto every authentication context the session
produces.
The authorization endpoint does not re-check the session’s liveness. A browser whose Laravel session is still alive past the absolute cap can still obtain an authorization code and a short-lived access token; only the refresh is refused. With Laravel’s idle lifetime normally far shorter than the absolute cap, the browser session is usually gone long before this matters.
Cookies and realms
Section titled “Cookies and realms”Which Laravel session the provider uses depends on realm routing:
single— the provider shares the application’s session: same cookie, same session id. Self-SSO depends on this, because Laravel’s CSRF cookie has one fixed name.path—ResolveRealmrenames the cookie to{session.cookie}-oidc-{realm}and scopes it to/realms/{realm}for the duration of the request, then restores both. Each realm gets its own browser session on the shared host.domain— each realm owns its origin, so the browser separates the cookies already and the package does nothing.
Pruning
Section titled “Pruning”oidc_sessions and oidc_session_participants grow one row per login and per participating client.
Schedule oidc:prune and oidc:dispatch-expired-session-logouts — see
Scheduled maintenance.
PurgeUser deletes a user’s session rows outright. It does not notify relying parties, so end the
sessions first when they should hear about it.