Skip to main content

Logout Flow

Ory Hydra implements OpenID Connect RP-Initiated Logout 1.0 and supports OpenID Connect Front-Channel Logout 1.0 and OpenID Connect Back-Channel Logout 1.0 flows.

A logout request may be initiated by the OpenID Provider (OP - you) or by the Relying Party (RP - the OAuth2 Client). Both requests follow the same pattern as user login and user consent. Before the logout is completed, the user is redirected to the Logout UI (similar to Login UI and Consent UI) to confirm the logout request.

A logout request can provide a id_token_hint and may optionally define state and post_logout_redirect_uri. Because of that there are several possible pathways for executing this flow, explained in the following diagram:

User Logout

Legend:

  • *: This is a query parameter, for example /oauth2/sessions/logout?id_token_hint=...
  • ** Here, an "active session" implies that there has been at least one login request completed with remember: true for that user. If that's not the case, the system "doesn't know" what to do (because there has never been a session issued that was remembered - hence it's not possible to forget it).
  • ***: Here, the "valid session cookies" implies that the browser has a valid authentication cookie when calling /oauth2/sessions/logout. If you have problems at this step, check if there is a cookie oauth2_authentication_session for the domain Ory Hydra is running at. Do not mix up IP (for example 127.0.0.1, 192.168.1.1) addresses and FQDNs (for example localhost, google.com).
  • ****: The post_logout_redirect defaults to the configuration value of urls.post_logout_redirect. If a post_logout_redirect_uri was set and that URL is in the array of the OAuth2 Client's urls.post_logout_redirect, the browser will be redirected there instead.

Logout Flow

User Logout Flow Diagram

  1. A user-agent (browser) requests the logout endpoint (/oauth2/sessions/logout). If the URL query contains an ID Token issued by Ory Hydra as the id_token_hint (/oauth2/sessions/logout?id_token_hint=...) then:
    • The URL query MAY contain key post_logout_redirect_uri indicating where the user agent should be redirected after the logout completed successfully. Each OAuth 2.0 Client can whitelist a list of URIs that can be used as the value using the post_logout_redirect_uris metadata field: /oauth2/sessions/logout?id_token_hint=...&post_logout_redirect_uri=https://i-must-be-whitelisted/
    • If post_logout_redirect_uri is set, the URL query SHOULD contain a state value. On successful redirection, this state value will be appended to the post_logout_redirect_uri. The functionality is equal to the state parameter when performing OAuth2 flows.
  2. The user-agent is redirected to the logout provider URL (configuration item urls.logout) and contains a challenge: https://my-logout-provider/logout?challenge=...
  3. The logout provider uses the challenge query parameter to fetch metadata about the request. The logout provider may choose to show a UI where the user has to accept the logout request. Alternatively, the logout provider MAY choose to silently accept the logout request.
  4. To accept the logout request, the logout provider makes a PUT call to /oauth2/auth/requests/logout/accept?challenge=.... No request body is required.
  5. The response contains a redirect_to value where the logout provider redirects the user back to.
  6. Ory Hydra performs OpenID Connect Front- and Back-Channel logout.
  7. The user agent is being redirected to a specified redirect URL. This may either be the default redirect URL set by urls.post_logout_redirect or to the value specified by query parameter post_logout_redirect_uri.

This endpoint doesn't remove any Access/Refresh Tokens.

Logout Provider Example (NodeJS Pseudo-code)

Following step 1 from the flow above, the user-agent is redirected to the logout provider (for example https://my-logout-provider/logout?challenge=...). Next, the logout provider fetches information about the logout request:

// This is node-js pseudo code and won't work if you copy it 1:1

challenge = req.url.query.logout_challenge

fetch('https://hydra/oauth2/auth/requests/logout?' + querystring.stringify({ logout_challenge: challenge }))
.then(function (response) {
return response.json()
})
.then(function (response) {
// ...
})

The server response is a JSON object with the following keys:

{
// The user for whom the logout was request.
"subject": "user-id",

// The login session ID that was requested to log out.
"sid": "abc..",

// The original request URL.
"request_url": "https://hydra/oauth2/sessions/logout?id_token_hint=...",

// True if the request didn't include a id_token_hint. False otherwise.
"rp_initiated": true | false
}

Next, the logout provider should decide if the end-user should perform a UI action such as confirming the logout request. It's RECOMMENDED to request logout confirmation from the end-user when rp_initiated is set to true.

When the logout provider decides to accept the logout request, the flow is completed as follows:

fetch('https://hydra/oauth2/auth/requests/logout/accept?' + querystring.stringify({ logout_challenge: challenge }), {
method: 'PUT'
})
.then(function (response) {
return response.json()
})
.then(function (response) {
// The response will contain a `redirect_to` key which contains the URL where the user's user agent must be redirected to next.
res.redirect(response.redirect_to)
})

You can also reject a logout request (for example if the user chose to not log out):

fetch('https://hydra/oauth2/auth/requests/logout/reject?' + querystring.stringify({ logout_challenge: challenge }), {
method: 'PUT'
}).then(function (response) {
// Now you can do whatever you want - redirect the user back to your home page or whatever comes to mind.
})

If the logout request was granted and the user agent redirected back to Ory Hydra, all OpenID Connect Front-/Back-channel logout flows (if set) will be performed and the user will be redirect back to his/her final destination.

OpenID Connect Front-Channel Logout 1.0

In summary (read the spec) this feature allows an OAuth 2.0 Client to register fields frontchannel_logout_uri and frontchannel_logout_session_required.

If frontchannel_logout_uri is set to a valid URL (the host, port, path must all match those of one of the Redirect URIs), Ory Hydra will redirect the user-agent (typically browser) to that URL after a logout occurred. This allows the OAuth 2.0 Client Application to log out the end-user in its own system as well - for example by deleting a Cookie or otherwise invalidating the user session.

Ory Hydra always appends query parameters values iss and sid to the Front-Channel Logout URI, for example:

https://rp.example.org/frontchannel_logout
?iss=https://server.example.com
&sid=08a5019c-17e1-4977-8f42-65a12843ea02

Each OpenID Connect ID Token is issued with a sid claim that will match the sid value from the Front-Channel Logout URI.

Ory Hydra will automatically execute the required HTTP Redirects to make this work. No extra work is required.

OpenID Connect Back-Channel Logout 1.0

In summary (read the spec) this feature allows an OAuth 2.0 Client to register fields backchannel_logout_uri and backchannel_logout_session_required.

If backchannel_logout_uri is set to a valid URL, a HTTP Post request with Content-Type application/x-www-form-urlencoded and a logout_token will be made to that URL when a end-user logs out. The logout_token is a JWT signed with the same key that's used to sign OpenID Connect ID Tokens. You should thus validate the logout_token using the ID Token Public Key (can be fetched from /.well-known/jwks.json). The logout_token contains the following claims:

  • iss - Issuer Identifier, as specified in Section 2 of [OpenID.Core].
  • aud - Audience(s), as specified in Section 2 of [OpenID.Core].
  • iat - Issued at time, as specified in Section 2 of [OpenID.Core].
  • jti - Unique identifier for the token, as specified in Section 9 of [OpenID.Core].
  • events - Claim whose value is a JSON object containing the member name http://schemas.openid.net/event/backchannel-logout. This declares that the JWT is a Logout Token. The corresponding member value MUST be a JSON object and SHOULD be the empty JSON object {}.
  • sid - Session ID - String identifier for a Session. This represents a Session of a User Agent or device for a logged-in End-User at an RP. Different sid values are used to identify distinct sessions at an OP. The sid value need only be unique in the context of a particular issuer. Its contents are opaque to the RP. Its syntax is the same as an OAuth 2.0 Client Identifier.
{
"iss": "https://server.example.com",
"aud": "s6BhdRkqt3",
"iat": 1471566154,
"jti": "bWJq",
"sid": "08a5019c-17e1-4977-8f42-65a12843ea02",
"events": {
"http://schemas.openid.net/event/backchannel-logout": {}
}
}

An exemplary Back-Channel Logout Request looks as follows:

POST /backchannel_logout HTTP/1.1
Host: rp.example.org
Content-Type: application/x-www-form-urlencoded

logout_token=eyJhbGci ... .eyJpc3Mi ... .T3BlbklE ...

The Logout Token must be validated as follows:

  • Validate the Logout Token signature in the same way that an ID Token signature is validated, with the following refinements.
  • Validate the iss, aud, and iat Claims in the same way they're validated in ID Tokens.
  • Verify that the Logout Token contains a sid Claim.
  • Verify that the Logout Token contains an events Claim whose value is JSON object containing the member name http://schemas.openid.net/event/backchannel-logout.
  • Verify that the Logout Token doesn't contain a nonce Claim.
  • Optionally verify that another Logout Token with the same jti value hasn't been recently received.

The endpoint then returns a HTTP 200 OK response. Cache-Control headers should be set to:

Cache-Control: no-cache, no-store
Pragma: no-cache

Because the OpenID Connect Back-Channel Logout Flow isn't executed using the user-agent (such as Browser) but from Ory Hydra directly, the session cookie of the end-user won't be available to the OAuth 2.0 Client and the session has to be invalidated by some other means (for example by blacklisting the session ID).