OpenID Connect (Authorization Code Flow) with Red Hat SSO

Patterns on the wall. / John

In this post, we are going to configure Red Hat SSO v7.1 for OpenID Connect (OIDC) with the Authorization Code Authentication Flow and demonstrate usage with a simple test application. Later, we are going to use this configuration as the basis for more sophisticated examples using 3Scale API Management.

OpenID Connect (and OAuth2) has emerged as the de facto standard for API, mobile applications, and modern Single Page Application (SPA) authentication and single sign-on, but it is flexible enough to be used in many other contexts. A typical use case for OIDC would be a SPA or mobile application that needs to authenticate an end user and then make API calls that also require authentication.

I’ve covered the details of the OIDC spec (and related specs) in a previous post, but let’s review the basic idea. From, “OpenID Connect 1.0 is a simple identity layer on top of the OAuth 2.0 protocol. It allows Clients to verify the identity of the End-User based on the authentication performed by an Authorization Server, as well as to obtain basic profile information about the End-User in an interoperable and REST-like manner.” This “REST-like manner” makes OIDC more like an API (in line with OAuth2) than the previous generations of OpenID. OIDC extends the OAuth2 Authorization Code Grant (three-legged OAuth).

OIDC builds on the lessons of the early OpenID protocols and SAML2 including:

  • Keep things simple
  • Build on top of OAuth2
  • Use easy-to-consume tokens (JWT)

OIDC can integrate with:

  • Traditional web applications
  • Mobile apps
  • Single Page Applications (SPA apps)
  • Server applications
  • Most other actors

Each of these application types have a corresponding authentication flow in the OIDC spec that is meant to be used. There is some overlap; as always, there is some gray area (checkout this blog post regarding which OAuth2 Implicit Grant should be used). Not every vendor uses the same authentication flows to satisfy each use case. At the end of the day, you have to work within the boundaries set by your Identity Provider vendor.


Let’s start with some assumptions to make sure we are all on the same page.

  • This document assumes basic familiarity with Red Hat SSO.
  • Your deployment of Red Hat SSO v7.1 will conform to the published supported configurations available here.
  • A Self-signed certificate is used for digital signatures on JWT tokens.
  • A local user is created for testing. An LDAP, database, or federation relationship with another IdP could also be used, but these are more advanced use cases with caveats that are outside the scope of this document.
  • We are simulating end user authentication and authorization of a typical web application with a server side component that is using the OIDC Authorization Code Authentication Flow with a confidential client.
  • So, we are configuring OIDC Authorization Code Authentication Flow (with a confidential client, i.e., has a client secret). Note, that the OAuth2 Authorization Code Grant is a subset of the OIDC Authorization Code Flow, so this blog post serves as an example of both.
  • We will use the OIDC test client available here to test the setup when we are done.
  • There will be no OAuth2 consent phase in this example.
  • The test application will not use the access token to access an external resource in this example.
  • Ideally, a supported Red Hat SSO Client Adapter would be used to interact with Red Hat SSO). However, only Java, Javascript, and node.js adapters are officially supported. For other platforms, a KeyCloak client (which is not officially supported) plugin appropriate for your platform would be used for all interaction with the IdP (Red Hat SSO) in the real case (see here). The Red Hat SSO documentation describes how to configure third-party OIDC client libraries.
  • Red Hat SSO is going to serve the authentication workflow (i.e., an interactive login).
  • For this example, the default Red Hat SSO login screen is used (this can be customized, if needed).

Red Hat SSO Instance Installation

Follow the instructions here to install Red Hat SSO v7.1. The installation details are outside the scope of this blog post.

Red Hat SSO Realm Setup Procedure

  • Enter a username and password with admin privileges.

  • Mouse over the “Select realm” drop down.
  • Click the blue Add Realm button.

  • Add the name “blog_demo”.
  • Click the Create button.

  • Make note of the OIDC endpoints by clicking on the OpenID Connect Endpoint configuration link in the Endpoints field. We’ll need several of these values later. For the blog_demo realm, we have:
"issuer": "",
"authorization_endpoint": "",
"token_endpoint": "",
"token_introspection_endpoint": "",
"userinfo_endpoint": "",
"end_session_endpoint": "",
"jwks_uri": "",
"check_session_iframe": "",
"grant_types_supported": [
"response_types_supported": [
"id_token token",
"code id_token",
"code token",
"code id_token token"
"subject_types_supported": [
"id_token_signing_alg_values_supported": [
"userinfo_signing_alg_values_supported": [
"request_object_signing_alg_values_supported": [
"response_modes_supported": [
"registration_endpoint": "",
"token_endpoint_auth_methods_supported": [
"token_endpoint_auth_signing_alg_values_supported": [
"claims_supported": [
"claim_types_supported": [
"claims_parameter_supported": false,
"scopes_supported": [
"request_parameter_supported": true,
"request_uri_parameter_supported": true
  • Click on the Keys tab.

  • Click the Providers tab.

  • Click the drop down.
  • Choose “rsa-generated”.

  • Change the “Console Display Name” to “blog-post-rsa-key-pair”.
  • Set priority to 100.
  • Click the Save button.
  • Click the Providers tab.

  • Click the Delete link next to the rsa-generated key pair.

  • Click the Delete button.

  • Note, if your organization has a key pair (with certificate issued out of an internal CA) that should be used for signing tokens, then that be uploaded using a similar set of steps.
  • Click on the Tokens tab.

  • Change the Access Token Lifespan to 60 minutes. The actual value used for a production application will depend on several factors. We are using 60 minutes here so that things do not timeout while completing the tutorial.
  • Change the Client login Timeout to 5 minutes. Once again, the default value of one minute is recommended; we are changing the value to five minutes so there is sufficient time to complete the steps in this tutorial.

Setup Red Hat SSO Client Configuration

  • Click the Clients link in the left-hand column.

  • Click the Create button.

  • Set the Client ID to “blog-post-demo-client-001”.
  • Set the Client Protocol to “openid-connect” (the default).
  • Click the Save button.

  • Set Consent Required to Off. We are not going to deal with user consent in this simple example — that will come later.
  • Set Access Type to Confidential
  • Set Standard Flow Enabled to On
  • Set Implicit Flow Enabled to On
  • Set Direct Access Grants enabled to On.
  • Set Service Accounts Enabled to On.
  • Set Valid Redirect URLs to “http://localhost:3000/callback”.
  • Click the Save button.

  • Scroll down to the Web Origins field at the bottom of the Settings tab.
  • Enter “http://localhost:3000/*”. If the base URL of the test client will be different, then use that URL here. Although, not recommmended, “*” can be used.
  • Click Save.

  • Click the Credentials tab.

  • Make note of the Secret value (this is the client secret).
  • Click on the Roles tab.

  • Click the “Add Role” button.

Create The Test User

  • Put “User” in the Role Name.
  • Put “The User role.” in the Description field.
  • Set “Scope Param Required” to Off. As long as the user is a member of a group that is mapped to the User role, the access token will show membership in this role.
  • Click the Save button.

  • Click on the Users link on the left-hand column.

  • Click the “Add user” button.

  • Add user1 to the Username field.
  • Click the Save button.

  • Click on the Credentials tab.

  • Add a password for this user to the “New Password” field (maybe, “password123”).
  • Reenter the same password into the “Password Confirmation” field.
  • Set Temporary to Off.
  • Click the red Reset Password button.

  • Click “Change Password”.

Create The Test Group

  • Click on the Groups link on the left-hand column.

  • Click the New button.

  • Enter Group1 in the name field.
  • Click Save.

  • Click the Role Mappings tab.

  • In the Client Roles drop down, choose “blog-post-demo-client-001”.

  • Select the User role from the “Available Roles” field.
  • Click the “Add selected” button.

  • Click on the Members tab.

  • Go back to the users section.

  • Click on the link for the user1 user.

  • Click on the Groups tab.

  • Select Group1 from the Available Groups list.
  • Click the Join button.

  • If you are following these instructions for another blog posts, you can stop here.

Test User Login with OpenID Connect

  • Follow the instructions here to setup the OAuth2 + OIDC Debugger app on your local machine. This is a simple test application that simulates the interaction between a real app and an IdP using the OAuth2 or OIDC protocols.
  • Open a browser tab and go to http://localhost:3000

  • Choose “OIDC Authorization Code Flow.
  • The screen will refresh. It will look very similar to the OAuth2 Authorization Code Grant option above.

  • Populate the Authorization Endpoint field with the URL from the meta data document we captured earlier (authorization_endpoint attribute).
  • Populate the Token Endpoint field with the URL from the meta data document we captured earlier (tokend_endpoint attribute).
  • Put the client identifier in the Client Id field (use “blog-post-demo-client-001”).
  • The default Redirect URL should work for this example (http://localhost:3000/callback).
  • Put “openid profile User” in the Scope field. The debugger automatically populates this field with “openid profile”.
  • For this example, a resource is not needed; so, leave “Add Resource field?” as “No”.
  • Click the Authorize button.
  • This will result in the following request being sent to Red Hat SSO:
scope=openid profile User
  • Red Hat SSO will prompt for credentials if there isn’t already an authenticated session.

  • Enter the username (User1) in the “Username or email” field.
  • Enter the password (password123) in the Password field.
  • Click the “Log in” button.
  • The IdP validates the credentials and returns an authorization code.
  • The callback endpoint refreshes the page and populates the Authorization Code field.

  • Put the client identifier in the Client ID field (use “blog-post-demo-client-001”).
  • Put the client secret in the Client Secret field.
  • Put “openid profile User” in the scope field.
  • A resource does not need to be specified in this example. So, leave “No” selected for the “Add Resource field?” question.
  • If your Red Hat SSO instance is using a self-signed certificate (or non-public CA), then choose “No” for “SSL Certificate Validation?”.
  • Click the “Get Token” button.
  • The debugger application sends the following request to the IdP:
scope=openid profile User
  • This will return a response with the access token, ID Token, refresh token, and other attributes.

  • This response from the IdP looks similar to the following (note, the tokens shown below have been corrupted so that you cannot see the original contents):
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOixAiSldUIiwia2lkIiA6ICJlbxng0N0FqcFdVRHhBWjRidkl4RFJGMXBlSnpPNnZpa0JvUW8x5U2MzYVVRIn0.eyJqdGkiOiIyNzk3Yzk3YS1jYTsMzLTQzxMdTMxtYjVlxZC00xNjcx1M4fTIzYzFiOTgiLCJleHAiOxjE1MTAzNjU2MTgsIm5iZiI6MCwxiaWF0IjoxNTEwMzY1MzE4LCJpc3MiOiJodHRwczovL2VjMi01Mi03Mi03MS0yMjkxuY29tcHV0ZS0xLmFtYXpvbmF3cy5jb206xODQ0My9hdXRoL3JlYWxtcy9ibG9nX2RlbW8iLCJhd6WQixOiJibG9nLXBvc3QtZGVtby1jbGllbn0QtMDAxIiwic3ViIjoxiNzFjOTA0ZjEtZTk3O8C00NTQyLTgwZGUtZmE5OGViYjI0MWU1IiwidHlwIjoiQmVhcmVyIxiwiYXpwIjoiYmxvZy1wb3N0LWRlbW8tY2xpZW50LTAwMSIsIm5vbmNlIjoiMWVmODdlZGMtNzZkYy00YWYzLWJmMmYtNWEzNzJjZTA2YmUyIiwiYXV0aF90aW1lIjoxNTEwMzYxMTYxLCJzZXNzaW9uX3N0YXRlIjoiYjY3M2M4M2YtYTY3Mi00M2YxLWFkMWItNjI2OG5E5N2M5MDMwIiwiYWNyIjoiMCIsIm987896NsaWVudF9zZXNzaW9uIjoiNTBmZWM2YWEtMzMyZS00MmU0LWFiM2UtMzE0YTU2NGJjYTBiIiwiYWxsb3dlZC1vcmlnaW5zIjpbIioiLCJodHRwOi8vbG9jYWxob3N0OjMwMDAiXSwicmVzb3VyY2VfYWNjZXNzIjp7ImJsb2ctcG9zdC1kZW1vLWNsaWVudC0wMDEiOnsicm9sZXMiOlsiVXNlciJdfX0sIm5hbWUiOiIiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJ1c2VyMSJ9.AYvnrPJ615eMNEWcr3zjD0auPgYr6ZsmYw1JR___0sTNW9YL3YyatEUttPAiJZNsr15s93xBp40svbv_GlZgsG57FZaYF0PNH79nbd8EzcrA_-M6vVED1mLQR9rd96Ec8ISCzEQhYcESBmOjI1ZZ2cFP05Uw1AfLI1CXWT9ExTbKknnahIYVLOeFJ2n9xr7JYgolBfeE4VksIktEk0hlUQf762nQ8uwZ4ycGBfHAZkLfvTodyQT5T3ulpNMg0_SSQDGmACKrq9YhG8wshw2PWWTjAMfnARvM5NiPCxGaf3qnFFz5bWjMbbDAyVKRmRYl1S8rJ2q1WBK9HkFH5fHIzng",
"expires_in": 300,
"refresh_expires_in": 1800,
"refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlbng0N0FqcFdVRHhBWjRidkl4RFJGMXBlSnpPNnZpa0JvUW85U2MzYVVRIn0.eyJqdGkiOiI4MWRjNGQ4NS1hMzdhLTRkZxmEtxOGNxiOC0zMxGE3OxDNiNDIxYzIiLCJleHAiOjE1MTAzNjcxMTxgsImx5ixZiI6MCxwiaWF0xIjoxNTEwMzY1MzE4LCJpc3MiOixJodHRxwczovL2VjxMi01Mix03Mi03MS0yMjkuY29tcHV0ZS0xLmFtYXpxvbmF3cy5jxb206ODQ0My9hdXRoL3JlYWxtcy9ibG9nX2RlbW8iLCJhdWQiOiJibG9xxnLXBvc3QtZGVtby1jbGllbnQtMDAxIiwic3ViIjoiNzFjOTA0ZjEtZTk3OC00NTQyLTgwZGUtZmE5OGViYjI0MWU1IiwidHlwIjoiUmVmcmVzaCIsImF6cCI6ImJsb2ctcG9zdC1kZW1vLWNsaWVudC0wMDEiLCJub25jZSI6IjFlZjg3ZWRjLTc2ZGMtNGFmMy1iZjJmLTVhMzcyY2UwNmJlMiIsImF1dGhfdGltZSI6MCwic2Vzc2lvbl9zdGF0ZSI6ImI2NzNjODNmLWE2NzItNDNmMS1hZDFiLTYyNjhhOTdjOTAzMCIsImNsaWVudF9zZXNzaW9uIjoiNTBmZWM2YWEtMzMyZS00MmU0LWFiM2UtMzE0YTU2NGJjYTBiIiwicmVzb3VyY2VfYWNjZXNzIjp7ImJsb2ctcG9zdC1kZW1vLWNsaWVudC0wMDEiOnsicm9sZXMiOlsiVXNlciJdfX19.PlZuB-TY_UasHdW-bEhC-uZQpTtm3-Jdnw5Gh5FIE8q6d3iAyUWyjHLrhL80z71XO8M8oeCW3Zjzd8QCPDbSyPJSiSCcDwgIRV7m0FKQJI-F7kBroYR-ADYi6SULl1Ul8PrOI0repgcLCVeaAkM07uXuIE2popMTbQzP1eZk7zjO0MvjUtBkk7UH-aAGV-75KarU0JQMLnKpu-DAp3A8fPmbgjLTu1eajj7DqAkcwJZWm7CefTzM3Kl5BRt4HiDcEsSbJfSVtPnlwmUoClholzu5-vgf7_5a8O-Alqn_SnRXuXkaaIRSL1ZZVCER-HuTLYWJFtRlXfbIbuiiktgAQg",
"token_type": "bearer",
"id_token": "eyJhbGciOiJSxUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlbng0N0FqcFdVRHhBWjRidkl4RFxJGMXBlSnpPNxnZpax0JvUWx85U2MzYVxVRInx0.eyJqdxGkiOiJiZmFlMx2M2OS1xiYzkxLxTQ5Y2IxtODM2Yi0zZxDNmMjJkYjxFhYzxMiLCJlxeHAiOjE1MxTxAzNjU2xMTgsIm5ixZiI6MCwiaxWF0IjoxNTExwMzY1MzEx4LCJpc3MiOiJodHRwczovL2VjMi01Mi03Mi03MS0yMjkuY29tcHV0ZS0xLmFtYXpvbmF3cy5jb206ODQ0My9hdXRoL3JlYWxtcy9ibG9nX2RlbW8iLCJhdWQiOiJibG9nLXBvc3QtZGVtby1jbGllbnQtMDAxIiwic3ViIjoiNzFjOTA0ZjEtZTk3OC00NTQyLTgwZGUtZmE5OGViYjI0MWU1IiwidHlwIjoiSUQiLCJhenAiOiJibG9nLXBvc3QtZGVtby1jbGllbnQtMDAxIiwibm9uY2UiOiIxZWY4N2VkYy03NmRjLTRhZjMtYmYyZi01YTM3MmNlMDZiZTIiLCJhdXRoX3RpbWUiOjE1MTAzNjExNjEsInNlc3Npb25fc3RhdGUiOiJiNjczYzgzZi1hNjcyLTQzZjEtYWQxYi02MjY4YTk3YzkwMzAiLCJhY3IiOiIwIiwibmFtZSI6IiIsInByZWZlcnJlZF91c2VybmFtZSI6InVzZXIxIn0.MnryJ_SXqi0FEZo5cfVEhsg8pLVy1nBrrtxud3bP7XWpINSkY6n6xQycWvOxhEBga2x82RM4qB6mcprgJm3LsBitjrV4X24AJyv1v2sBp1xX0skgKVLyD70UTFRhL9q-koJTu4CMCIich-wmFnhrRnzUujafLVL61LVS41keVfScRdOofDHoAZBXicwhHIi5SM9Poo16EIsHgh31_i9AKsX7gkaZskgx_erJe1ArAmxxVf23LPkYpcQM-4R6aEN_jZ9JQowHZmLbj7zltvbATApTFMQ6SoswhtnA8bVezT3P-PC2didkeSNzTyKYhyUviuN1fASm7T2zj58ZCy-b2Q",
"not-before-policy": 0,
"session_state": "b673c83f-a672-43f1-ad1b-6268a97c9030"
  • The OAuth2 access token is stored in the access_token attribute. This is a JWT token. The JWT payload contains:
"jti": "2797c97a-ca33-4313-b5ed-4675123c1b98",
"exp": 1510365618,
"nbf": 0,
"iat": 1510365318,
"iss": "",
"aud": "blog-post-demo-client-001",
"sub": "71c904f1-e978-4542-80de-fa98ebb241e5",
"typ": "Bearer",
"azp": "blog-post-demo-client-001",
"nonce": "1ef87edc-76dc-4af3-bf2f-5a372ce06be2",
"auth_time": 1510361161,
"session_state": "b673c83f-a672-43f1-ad1b-6268a97c9030",
"acr": "0",
"client_session": "50fec6aa-332e-42e4-ab3e-314a564bca0b",
"allowed-origins": [
"resource_access": {
"blog-post-demo-client-001": {
"roles": [
"name": "",
"preferred_username": "user1"

You can see that the JWT token describes a user called “user1” and that it is a member of the User role.

An alternative testing mechanism is to run the following shell script that simulates at the calls made to the IdP for the Authorization Code Flow.

#set -x
CURL_OUTPUT=`curl -X GET "${IDP_BASE_URL}/auth?client_id=${CLIENT_ID}&response_type=code&scope=openid%20profile%20email&state=${STATE}&redirect_uri=${FINAL_REDIRECT_URI}" --insecure -D headers.out`
PASSWORD_SUBMIT_URL=`echo $CURL_OUTPUT | awk '{print $100 }' | cut -c 8- | sed 's/"//g'`
CURL_OUTPUT=`curl -X POST "${PASSWORD_SUBMIT_URL}" -d "username=${USERNAME_}&password=${PASSWORD_}" --insecure -D /var/tmp/headers.out`
echo /var/tmp/headers.out
REDIRECT_URL=`cat /var/tmp/headers.out | grep ^Location | cut -c10-`
CODE=`echo $REDIRECT_URL | awk -F"?" '{ print $2 }' | awk -F"&" '{print $2}' | awk -F"=" '{print $2}' | sed 's/r//g'`
CURL_OUTPUT=`curl -X POST "${IDP_BASE_URL}/token" -d "state=${STATE}&code=${CODE}&grant_type=authorization_code&client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}&redirect_uri=${FINAL_REDIRECT_URI}" --insecure -D headers.out`
ACCESS_TOKEN=`echo ${CURL_OUTPUT} | python -c "import sys, json; print json.load(sys.stdin)['access_token']"`
echo "-------------------------------------"
echo "-------------------------------------"
ID_TOKEN=`echo ${CURL_OUTPUT} | python -c "import sys, json; print json.load(sys.stdin)['id_token']"`
echo "-------------------------------------"
echo "-------------------------------------"
REFRESH_TOKEN=`echo ${CURL_OUTPUT} | python -c "import sys, json; print json.load(sys.stdin)['refresh_token']"`
echo "-------------------------------------"
echo "-------------------------------------"

The output of this script will look something like:


You can customize this script to work with your IdP and client by updating:


In future blog posts, we’ll look at the other OAuth2 Grants and OIDC flows that are supported by Red Hat SSO, integration with 3Scale, and explore the RH SSO implementation details of the specs.

Image: Patterns on the wall. / John

Leave a Reply

Your email address will not be published. Required fields are marked *