Single logout¶
A session of the provider can be ended from either side. A service provider asks for it with a
LogoutRequest; or the session ends at the provider, and every service provider that signed in under it is
told. Both go through the browser, the front channel of the Single Logout profile over HTTP-Redirect and
HTTP-POST (SAML Profiles §4.4.3), at the single logout service of the tenant, /saml/slo.
A logout a service provider asks for¶
The request is the service provider's, signed. A LogoutRequest is accepted from a declared service
provider whose accepted metadata list a single logout service it can be answered at, and only signed, in its
XML or over the query string of HTTP-Redirect, under the keys of its metadata (SAML Profiles §4.4.4.1). A
declaration that says its sign-on requests are unsigned relaxes nothing here, and no setting does. A request
that is refused ends nothing and gets no SAML answer: the browser is shown the page of a refusal.
Accepted once. The issuer and the ID of every request accepted are remembered until the window in which
it would be accepted again has closed, eight minutes at most, in one store every worker of the deployment
shares. The same request presented again ends nothing.
The sessions it names, of the person it names. A SessionIndex is the identifier of a session, the one
the assertion carried, and a request names up to sixteen. A session is ended only when its user is the
person of the NameID, a persistent identifier the provider computes again for that service provider and
compares, never one it looks up.
| The request | The status of the answer |
|---|---|
| Names sessions of that person, or sessions that have ended already, or that do not exist | Success |
| Names a session of another person | Requester, UnknownPrincipal, and no session of the request ends |
Names no SessionIndex |
Requester, RequestUnsupported, and nothing ends |
The sessions end as every session ends, at once and before the answer is written, since the answer says whether they ended (SAML Core §3.7.3.2). The clients of OpenID Connect that signed in under them are told by the back channel, their refresh tokens are revoked and their opaque access tokens removed, exactly as when the session ends at the end session endpoint. The other service providers of the session are told through the browser, in the chain below, before the one that asked is answered.
The answer goes where the metadata say. A signed LogoutResponse, to the first single logout service the
accepted metadata list on the binding the request came over, or else the first one listed, at its
ResponseLocation when it has one (SAML Metadata §2.2.2), never to an address the request carries. Its
RelayState is the one received, byte for byte, and its status says PartialLogout under Success when one
of the other service providers did not log out.
A key management service that does not answer when the signing key is opened ends nothing and answers
503: no session ends whose answer cannot be signed.
The provider tells the others¶
The chain starts wherever a browser ends the session it holds:
- the end session endpoint of OpenID Connect, once it has ended the session (RP-Initiated Logout 1.0 §2);
- the sessions page of the account, when the session closed is the one of the browser reading it;
- the single logout service, when a service provider's request ended sessions.
sequenceDiagram
autonumber
participant B as Browser
participant P as Beffroi
participant S1 as Service provider 1
participant S2 as Service provider 2
B->>P: Ends the session
P->>B: The front-channel logout page of the OpenID Connect clients
P->>B: LogoutRequest for service provider 1
B->>S1: LogoutRequest
S1->>B: LogoutResponse
B->>P: LogoutResponse
P->>B: LogoutRequest for service provider 2
B->>S2: LogoutRequest
S2->>B: LogoutResponse
B->>P: LogoutResponse, then where the logout ends
The session has ended before the chain begins. Whatever becomes of the chain, a service provider that never answers or a browser closed half way, nothing of the provider stays open.
The OpenID Connect clients first. The browser is given the front-channel logout page of the ended
sessions, one frame per client that registered a frontchannel_logout_uri (Front-Channel Logout 1.0 §2),
and then goes on to the service providers.
Every service provider of the session, but the one that asked, session by session, in the order they
first signed in. Each is sent a signed LogoutRequest: a new ID, valid five minutes, the persistent
NameID computed again for it, one SessionIndex, and no RelayState, its answer being found by its
InResponseTo. It goes to the first single logout service of its metadata, read again when it is written.
Its LogoutResponse is read before the next one is told: signed, from that service provider, for that
request. A status other than Success is an answer and not a refusal, and the chain goes on.
Passed over, and counted as a service provider that did not log out: one the configuration no longer declares, one whose metadata no longer read, one with no single logout service on HTTP-Redirect or HTTP-POST, one whose request cannot be written.
Kept by the provider, played once, by the browser that began it. Where the chain stands is a row of the
provider and nothing the browser holds, since the session cookie no longer exists and an answer posted from
another site arrives without it. The row is bound to the browser that began the chain by a cookie of its
own, __Host-beffroi_saml_logout: Secure, HttpOnly, its path /, no Domain, SameSite=None because
an answer over HTTP-POST is a post from another site, and worth the ten minutes the chain stays open, renewed
at every step. A step presented without it, by the server of a service provider or by anybody who read a URL
in a log, moves nothing.
Where it ends. For a logout a service provider asked for, its LogoutResponse. For the end session
endpoint, the post_logout_redirect_uri with its state, as RP-Initiated Logout 1.0 §3 builds it, or the
page that says the browser is signed out. For the page of the account, that page.
A service provider that never answers holds the browser where it is: the chain closes ten minutes after its last step, the service providers after it are not told, and the one that asked gets no answer. Nothing of the provider is held open by it.
What a logout can promise¶
A session ended without its browser tells no service provider. The console, the page of the account read in another browser, closing every other session of an account, a new login that replaces a session: the clients of OpenID Connect learn it by the back channel, and a service provider has no channel without the browser, SOAP being out of scope.
Every end of a session revokes what was issued under it, whatever ended it: the refresh tokens of OpenID Connect issued in the session are revoked and its opaque access tokens removed.
The pages that start a chain name where it goes. The confirmation page of the end session endpoint and
the sessions page of the account name, in their form-action, the origin of the single logout service each
service provider of the session would be told at. A browser checks that directive over every redirection of
a submission, and the chain is a series of them.