Managing Sessions with OpenID Connect

OpenID connect session management specification defines a protocol-bound approach for the OpenID clients to verify the identity of the already authenticated end-users at the authorization server and to obtain their basic profile information via a REST-ful manner. Furthermore it defines methodologies to manage user sessions and log-out end-users at the authorization server. OpenID Connect session management uses front-channel communication. That means the login/logout requests from the RP to OP and OP to RP is done via the User Agent (browser based).

First of all, we need to understand some openid connect specific terms that are used throughout the article.

Relying party (RP) : OAuth 2.0 Client application requiring End-User Authentication and user claims from an OpenID Provider (OP).

OpenID Provider (OP) : OAuth 2.0 Authorization Server that is capable of Authenticating the End-User and providing Claims to a Relying Party about the Authentication event and the End-User.

Session : Continuous period of time during which an End-User accesses a Relying Party relying on the Authentication of the End-User performed by the OpenID Provider.

Now let’s see how to monitor the end-user’s login status at the OP continuously such that RP can logout an End-User who is already logged out from the OP.

Following approaches can be used to obtain information regarding the login status at the OP.

  • Using ‘exp’ attribute of the ID Token — An ID Token typically comes with an expiration date. If the RP wants to terminate a session when the OP session terminates (due to timeout or user logging out), RP may rely on the id token to expire the RP session. However, it is entirely possible that the End-User might have logged out of the OP before this expiration date. Therefore, the best approach is to find out the login status of the End-User at the OP. For this the RP must periodically check on the session status on the OP.
  • Repeating Passive Authentication Requests against the OP Authorization Endpoint with the prompt=none parameter added — this is by far the simplest approach. However, the spec points out that this approach will generate additional network traffic that may not be desirable.
  • Polling a hidden OP iframe from an RP iframe with an origin restricted postMessage — This mechanism will not cause any additional network traffic. Therefore this method is elaborated in the OIDC Session Management specification as a solution to this .

OpenIDConnect uses following two endpoints to manage user sessions. Any Authorization Server implementing OIDC Session Management MUST support these two endpoints.

check_session_iframe — URL of an OP iframe that supports cross-origin communications for session state information with the RP Client, using the HTML5 postMessage API. The page is loaded from an invisible iframe embedded in an RP page so that it can run in the OP’s security context. It accepts postMessage requests from the relevant RP iframe and uses postMessage to post back the login status of the End-User at the OP.

end_session_endpoint — URL at the OP to which an RP can perform a redirect to request that the End-User be logged out at the OP

Session State

When the OP supports session management, it MUST also return the session state at the OP, as an additional session_state parameter in the Authentication Response. RP uses this session state value to monitor end user session at the OP.

The session_state value contains “a salted cryptographic hash of Client ID, origin URL, and OP browser state”.

For the origin URL, the server can use the origin URL of the Authentication Response.

var session_state = CryptoJS.SHA256(client_id + ' ' + e.origin + ' ' + op_browser_state + ' ' + salt) + "." + salt;

When a user initially authenticates to the OP (authorization server) via an RP (OAuth client application), above session value is calculated on the server. This is sent back to the RP with the authentication response.

Let’s see how this session status is utilized at the RP to validate user session status.

Polling OP iframe from an RP iframe to learn OP session status

The RP loads an invisible iframe from itself for RP iframe and it also loads an invisible OP iframe into itself from the OP’s check_session_iframe endpoint.

This RP iframe must know the ID of the OP iframe so that it can post messages to the OP iframe via HTML5 postMessage(). RP iframe calls Window.postMessage() on the OP iframe to determine if the end user session is still valid at the OP. RP Iframe should send the client_id and session state values with each of these requests.

The OP iframe must enforce that the caller has the same origin as its parent frame. It must reject postMessage requests from any other source origin.

RP iframe should continuously post messages (poll) to the OP iframe at an interval as per the application requirements.

The OP iframe has access to Browser state at the OP (in a cookie or in HTML5 storage) that it uses to calculate and compare with the OP session state that was passed by the RP with each request.

The OP iframe recalculates the current session status from the Client ID (sent with the request), the source origin URL (from the postMessage), and the current OP Browser state (e.g. session cookie value if a cookie is used to manage browser state). The session state includes all of this information for privacy reasons, so that different clients active in the same Browser have distinct session state values.

If the postMessage received is syntactically malformed in such a way that the posted Client ID and origin URL cannot be determined or are syntactically invalid, then the OP iframe returns the string ‘error’ back to the source. If the received value and the calculated value do not match, then the OP iframe postMessage the string ‘changed’ back to the source. If it matched, then it MUST postMessage the string ‘unchanged’

RP iframe should be able to receive the postMessage back from the OP iframe. The received data will be either of following string values.

  • changed’ — Indicates that session has changed at the OP. This can happen due to user logout, session timeout or user logging in from a different client application. Upon receipt of changed, the RP performs re-authentication with prompt=none to obtain the current session state at the OP.
  • unchanged’ — This indicates that user-session is still valid at the OP. RP will continue to poll OP iframe to detect any session changes.
  • error’ — If syntax of the message sent was determined by the OP to be malformed, received data will be error. Upon receipt of error, the RP must not perform re-authentication with prompt=none, so as to not cause potential infinite loops that generate network traffic to the OP.

When the RP detects a session state change when it receives a ‘changed’ in response, it will first try a prompt=none request within the RP iframe to obtain a new ID Token and the current session state of the user. It should send the old ID Token as the id_token_hint parameter which is required to obtain information about the authenticated user at the OP. If the RP receives an ID token for the same End-User, it will simply update the value of the session state to the new value. If it doesn’t receive an ID token or receives an ID token for another End-User, that means that user has logged out of the application, user session has expired or that user logged in as another user from another RP. Therefore it needs to handle this case as a logout for the original End-User.

As the session state is origin bound it will be returned with authentication failure response as well.

Following diagram illustrates the above scenarios.

OP Browser State

The OP browser state is typically going to be stored in a cookie or HTML5 local storage. It is origin bound to the Authorization Server. It captures meaningful events such as logins, logouts, change of user, change of authentication status for Clients being used by the End-User, etc. Thus, the OP SHOULD update the value of the browser state in response to such meaningful events. As a result, the next call to check_session() after such an event will return the value changed. It is RECOMMENDED that the OP not update the browser state too frequently in the absence of meaningful events so as to spare excessive network traffic at the Client in response to spurious changed events.

The computation of the session state returned in response to unsuccessful Authentication Requests SHOULD, in addition to the browser state, incorporate sufficient randomness in the form of a salt so as to prevent identification of an End-User across successive calls to the OP’s Authorization Endpoint.

In the case of an authorized Client (successful Authentication Response), the OP SHOULD change the value of the session state returned to the Client under one of the following events:

  • The set of users authenticated to the browser changes (login, logout, session add).
  • The authentication status of Clients being used by the End-User changes.

In addition, the browser state used to verify the session state SHOULD change with such events. Calls to check_session() will return changed against earlier versions of session state after such events. It is RECOMMENDED that the browser state SHOULD NOT vary too frequently in the absence of such events to minimize network traffic caused by the Client’s response to changed notifications.

In the case of an unsuccessful Authentication Request, the value of the session state returned SHOULD vary with each request. However, the browser session state need not change unless a meaningful event happens. In particular, many values of session state can be simultaneously valid, for instance by the introduction of random salt in the session states issued in response to unsuccessful Authentication Requests.

If a cookie is used to maintain the OP browser state, the HttpOnly flag likely can’t be set for this cookie because it needs to be accessed from JavaScript. Therefore, information that can be used for identifying the user should not be put into the cookie, as it could be read by unrelated JavaScript.

In some implementations, changed notifications will occur only when changes to the End-User’s session occur, whereas in other implementations, they might also occur as a result of changes to other sessions between the User Agent and the OP.

RP-Initiated Logout

An RP can notify the OP that the End-User has logged out of the site and might want to log out of the OP as well. In this case, the RP, after having logged the End-User out of the RP, redirects the End-User’s User Agent to the OP’s logout endpoint URL. This URL is obtained via the end_session_endpoint described above.

Following parameters are optional and recommended to be passed as query parameters in the logout request.

  • id_token_hint — Previously issued ID Token passed to the logout endpoint as a hint about the End-User’s current authenticated session with the Client. This is used as an indication of the identity of the End-User that the RP is requesting be logged out by the OP. The OP need not be listed as an audience of the ID Token when it is used as an id_token_hint value.
  • post_logout_redirect_uri — URL to which the RP is requesting that the End-User’s User Agent be redirected after a logout has been performed. The value MUST have been previously registered with the OP, either using the post_logout_redirect_uris Registration parameter or via another mechanism. If supplied, the OP SHOULD honor this request following the logout.
  • state — Opaque value used by the RP to maintain state between the logout request and the callback to the endpoint specified by the post_logout_redirect_uri query parameter. If included in the logout request, the OP passes this value back to the RP using the state query parameter when redirecting the User Agent back to the RP.

Software Engineer | GSoC Intern | CSE Graduate