Invoking the Session Management Endpoint for OpenID Connect

The session management endpoint enables OpenID Connect Relying Parties to monitor the login status of a user with a particular OpenID Connect Provider (OP) while minimizing network traffic. With the help of the session management endpoint, a Relying Party (RP) can log out a user who logged out of the OpenID Connect Provider.

Before you begin

The OP session management endpoint URL is obtained from the check_session_iframe attribute in the discovery information that is returned from the discovery endpoint of the OP. This URL must be used as the target of an iframe in the RP application that requires session management functionality. The RP application must also know the id attribute of the iframe in order to submit Window.postMessage() requests to it.

About this task

To help determine the login status of a user, the RP loads an iframe with its src target set to the session management endpoint of the OP. The session management endpoint has access to a cookie that stores the login status, or browser state, of a user. This browser state cookie is updated when a user logs out of the OP. The RP can then use client side scripting to invoke the Window.postMessage() function of the OP iframe, sending the client ID and the currently known session state in the text of the message. If the RP receives a postMessage back from the OP frame with a value of changed, then the login status of the user at the OP has changed and the RP can decide whether to log out the user. If a value of unchanged is returned, the user is still logged in at the OP.

A Liberty server with OpenID Connect enabled has access to the OpenID Connect session management endpoint at the following URL:

https://server.example.com:443/oidc/endpoint/<provider_name>/check_session_iframe
Avoid trouble: If you are using an outbound proxy, note that the OpenID Connect RP does not provide a means to route requests through a proxy host automatically.

If you must use a proxy to access the OpenID Connect Provider (OP), the value that you enter for any OP-related URL property must contain the proxy host and port, not the external OP host and port.

In most cases, you can replace the OP host and port with the proxy host and port. The URL that you enter must be visible to both the RP and client (browser or application). For further guidance on how to determine the correct URL to use, contact your proxy administrator.

In this example, the client expects the SSL port to be set to 443.

Procedure

  1. Create a web resource in an appropriate RP application capable of loading an iframe that targets the OP session management endpoint. The web resource also needs to have access to the session state value that is returned in the session_state parameter of the authorization response. The session state value can be stored in a cookie, for example, or in any other way that allows client-side scripting in the web resource to know what the value is. The following is a sample HTML snippet for such an iframe.
    <iframe id="iframeOP" src="https://server.example.com:443/oidc/endpoint/OidcConfigSample/check_session_iframe" frameborder="0" width="0" height="0"></iframe>
    
  2. To check the login status of a user, invoke the Window.postMessage() function of the OP iframe, passing the client ID and session state as the message parameter in the format Client ID + " " + Session State and the host name of the OP as the target origin parameter. In the following JavaScript sample function, the script expects the session state value to be stored in a cookie that is named session_state, and the getCookieValue() function returns the value that is stored in the session_state cookie.
    	var targetOP = "https://server.example.com:443";
    	function checkStatus() {
               var client = "client01";
               var sessionState = getCookieValue("session_state");
               var text = client + " " + sessionState;
               var iframe = document.getElementById("iframeOP");
               iframe.contentWindow.postMessage(text, targetOP);
    	}
  3. Configure the web resource to listen for postMessages from the OP that contain the value changed or unchanged to reflect the respective login status of the user. The RP can then decide whether to log the user out of the RP based on the value that is returned from the OP. The function must ensure that the origin of the postMessage matches the expected OP host name. Any messages that do not match are rejected. The following JavaScript example shows how to add an event listener to the web resource to listen for such messages.
    	var targetOP = "https://server.example.com:443";
    	window.addEventListener("message", receiveMessage, false);
    	function receiveMessage(event) {
               if (event.origin !== targetOP) {
                         // Origin did not come from the OP; this message must be rejected.
                         return;
               }
               if (event.data === "unchanged") {
                         // User is still logged in to the OP
               } else {
                         // User has logged out of the OP
               }
    	}

Results

You now have a web resource on the RP that is capable of utilizing the session management functionality of OpenID Connect on a Liberty server OP. The browser state that is maintained in the OP iframe is updated when users log in or log out of the OP. After successful login at the OP, a new session state value is provided in the authorization response to the RP. The RP can then use client-side scripting to validate the session state of the user to determine whether the login status of the user changed on the OP without broadcasting extra network traffic.

Example

The following HTML example shows a complete HTML page that uses OpenID Connect Session Management. The src attribute of the OP iframe is set to the session management endpoint URL obtained from the OP. The startChecking() function is automatically called every 60 seconds and checks the login status of the user. The page has a message event listener that calls the receiveMessage() function when a postMessage is received. This function makes sure the postMessage comes from the expected domain for the OP and checks the value of the returned message to see whether the login status of the user is changed or unchanged.

You can load this HTML page, itself, as an invisible iframe in another web resource within the RP. This enables any web resource that loads this iframe to monitor the login status of the user on the client side.
	<!DOCTYPE html>
	<html>
	<head>
	<meta charset="ISO-8859-1">
	<title>iFrame RP Page</title>
	</head>
	<body onload="javascript:startChecking()">
            <iframe id="iframeOP" src="https://localhost:8999/oidc/endpoint/OidcConfigSample/check_session_iframe" frameborder="0" width="0" height="0"></iframe>
	</body>
	<script>
            var targetOP = "https://server.example.com:443";
		
            window.addEventListener("message", receiveMessage, false);
		
            function startChecking() {
                      checkStatus();
                      // Check status every 60 seconds
                      setInterval("checkStatus()", 1000*60);
            }
		
            function getCookieValue(cookieName) {
                      var name = cookieName + "=";
                      var cookies = document.cookie.split(';');
                      if (!cookies) {
                                return null;
                      }
                      for (var i = 0; i < cookies.length; i++) {
                                var cookie = cookies[i].trim();
                                if (cookie.indexOf(name) == 0) {
                                          return cookie.substring(name.length, cookie.length);
                                }
                      }
                      return null;
            }
		
            function checkStatus() {
                      var client = "client01";
                      var sessionState = getCookieValue("session_state");
                      var text = client + " " + sessionState;
                      var iframe = document.getElementById("iframeOP");
                      iframe.contentWindow.postMessage(text, targetOP);
            }
		
            function receiveMessage(event) {
                      if (event.origin !== targetOP) {
                                // Origin did not come from the OP; this message must be rejected
                                return;
                      }
                      if (event.data === "unchanged") {
                                // User is still logged in to the OP
                      } else {
                                // User has logged out of the OP
                      }
            }
	</script>
	</html>