Front-channel logout
All domains, identifiers, and tokens in these examples are fictional.
Lantern Studio's designers use two applications through Lantern's identity provider at https://idp.lantern.example: the project portal at https://portal.lantern.example, and the timesheets application at https://time.lantern.example. A designer signs in once in the morning, and single sign-on carries them into both.
At the end of Thursday, designer-42 selects Sign out in the portal on a shared workstation in the studio. The portal uses RP-initiated logout, as the printer did, and Lantern's identity provider ends its session. The timesheets application, still open in another tab, knows nothing about it. Its session would last until its own timeout, and the next person at the workstation could open that tab and record hours as designer-42.
Only the provider knows that both applications were part of the session it just ended. Front-Channel Logout lets it pass the news on through the browser that is already at its sign-out page.
Logging out through the browser
To notify anyone, the provider has to remember whom to notify. Lantern's provider records each application that signs in through each of its sessions. For the session it identifies as demo-session-58, the list holds lantern-portal and lantern-timesheets.
Each application has registered a front-channel logout URI, a page on its own site that ends its session when it is loaded. The timesheets registration includes:
{
"client_id": "lantern-timesheets",
"frontchannel_logout_uri": "https://time.lantern.example/logout/front-channel",
"frontchannel_logout_session_required": true
}
The address must use the same scheme, host, and port as one of the application's registered redirect URIs, which ties it to a site the registration already trusts. frontchannel_logout_session_required asks the provider to add two query parameters when it loads the page: iss, its issuer identifier, and sid, the session that ended. A provider that can send them also puts the same sid in the ID tokens it issues, so each application already holds the value in its session record. Lantern's provider uses one value for every application signed in through a browser session. Another provider might give each application its own; either way, an application only compares the value with the one it stored.
After ending its session, the provider shows a signed-out page. Inside it is a hidden frame for each application on the list:
<p>You are signed out of Lantern.</p>
<iframe hidden src="https://portal.lantern.example/logout/front-channel?iss=https%3A%2F%2Fidp.lantern.example&sid=demo-session-58"></iframe>
<iframe hidden src="https://time.lantern.example/logout/front-channel?iss=https%3A%2F%2Fidp.lantern.example&sid=demo-session-58"></iframe>
The browser loads every frame at once, and each request carries the provider's issuer and the session ID to one application. The portal is on the list even though it started the sign-out, because RP-initiated logout includes the initiating application in these notifications. It has already ended its own session, and a logout request for a session that is already gone counts as a success. Once the frames have loaded, the provider sends the browser on to the portal's registered post-logout address.
The logout page
When the request reaches https://time.lantern.example/logout/front-channel, the timesheets application:
- Checks that
issis exactlyhttps://idp.lantern.example, the issuer it is configured to trust. - Looks for sessions whose stored issuer and
sidmatch. The specification allows an application to ignore a request that matches none of its current or recent sessions. - Ends each matching session on its server, and clears its session cookie and anything it keeps in browser storage for that session.
- Responds with a short page and tells caches not to store it.
HTTP/1.1 200 OK
Content-Type: text/html
Cache-Control: no-store
Content-Security-Policy: frame-ancestors https://idp.lantern.example
Set-Cookie: __Host-timesheets-session=; Path=/; Max-Age=0; Secure; HttpOnly; SameSite=Lax
Cache-Control: no-store keeps a stored copy of this response from answering a future logout request, which would then never reach the application. The Content-Security-Policy line matters for a different reason. Many applications refuse to be displayed inside another site's frame, as a defense against clickjacking, where a page frames an application invisibly and tricks people into clicking its buttons. That is the right default for timesheets, but this one page must let Lantern's provider frame it, or the browser will block the page and the sign-out will never happen.
Notice what the page relies on. The request is an ordinary GET, which any website could load in a frame or an image tag. If the logout page simply ended whatever session its cookie pointed to, any page designer-42 visited could sign them out of timesheets. Matching sid limits the request to the session the provider named, and providers generate session IDs with enough randomness that nobody can guess someone else's. A stranger without the value has nothing useful to send.
Why it often fails
Every step of front-channel logout happens in the designer's browser, and the provider learns nothing about the result. A frame from another origin does not report whether the page inside it succeeded, so the provider can tell at most that something loaded. If designer-42 closes the tab before the frames finish, the network drops, or an application is briefly down, the request is lost. Nobody retries it, because nobody knows it failed.
Lantern's setup is also kinder than most. Browsers decide what counts as third-party by site, the registrable domain such as lantern.example, not by the full host name. Lantern's provider, portal, and timesheets are all subdomains of lantern.example, so their frames are same-site. The browser sends each application its cookies, and storage inside the frame is the same storage the application sees in its own tab.
Now imagine the printer had registered for front-channel logout with the photo service instead of back-channel. Its logout page would load in a frame inside a page at auth.photos.example, a different site. The printer's __Host-printer-session cookie is marked SameSite=Lax, and browsers do not send a Lax cookie with a request for a cross-site frame. Changing it to SameSite=None would expose it to every cross-site request, which is what Lax exists to prevent, and it still would not be enough. Some major browsers block third-party cookies by default or keep a separate cookie jar for each top-level site, the others let people turn third-party cookies off, and current browsers partition web storage such as localStorage in cross-site frames. The printer's frame would see none of its own browser state.
The specification warns about exactly this, and recommends that deployments detect when an application could not be signed out and, where possible, tell the person. The sid parameter helps more than it first appears. The request itself still reaches the printer's server, cookie or not, so an application that keeps its sessions on the server can find and end the right one from iss and sid alone. An application that keeps its session entirely in the browser, such as a single-page app holding tokens in memory or storage, has no such fallback.
Front-channel logout still serves organizations like Lantern, whose applications share a site with their identity provider, as a quick way to clear browser state when it works. For a sign-out that must happen, such as ending a departing employee's sessions, the provider needs a path that does not depend on a browser at all.