OpenID Connect Hybrid Flow

Hasini Witharana
Identity Beyond Borders
4 min readNov 23, 2017

Why do we need a hybrid flow?

Before giving an answer for this we need to look at basic and implicit flows in the OpenID Connect.

In basic flow a code is returned via front channel and client id and client secret is needed for the client authentication. Then the access token is issued form token endpoint and shared to client via back channel.

In implicit flow requested tokens are generated at authorization end point and do not require client secret for client authentication. This process happens via front channel.

Following table shows the use cases of basic(authorization code) and implicit flow.

For more information you can read my previous blog , where I explained the basics of the OpenID Connect.

What if we want tokens separately from the front channel and backchannel? The solution is a hybrid flow.

In hybrid flow, we can request combinations of code, id_token and token. There are three combinations for hybrid flow defined in OIDC specification.

  1. response type = code token
  2. response type = code id_token
  3. response type = code id_token token

Let's go through each of these.

Code Token

In this response type, we request a code and an access token from the authorization endpoint.

Example of Authorization request

https://localhost:9443/oauth2/authorize?response_type=code token&client_id=<Client ID>&nonce=asd&redirect_uri=http://localhost:8080/playground2/oauth2client&scope=openid

Example of a Successful Authorization Response

http://localhost:8080/playground2/oauth2client#access_token=1940a308-d492-3660-a9f8-46723cc582e9&code=99b34587-5483-374d-8b25-50485498e761&token_type=Bearer&expires_in=299999&session_state=baae9a71cdabe38b4643b9d59bd9f65ffaf5a9b8c453f4256c085e5a1c57e624.-EA3ZqPzLvsk25CKmt56YA

By sending the code to the token endpoint we can request an access token, refresh token and id_token.

Here is the curl command for requesting tokens from token endpoint.

curl -k -v — user <Client ID>:<Client secret> -d “grant_type=authorization_code&code=99b34587–5483–374d-8b25–50485498e761&redirect_uri=http://localhost:8080/playground2/oauth2client" https://localhost:9443/oauth2/token

Below is the response from token endpoint.

{“access_token”:”1940a308-d492–3660-a9f8–46723cc582e9",”refresh_token”:”6b96cc3a-00da-3d7d-acd1–5aaf76dcd9d4",”scope”:”openid”,”id_token”:”eyJ4NXQiOiJOVEF4Wm1NeE5ETXlaRGczTVRVMVpHTTBNekV6T0RKaFpXSTRORE5sWkRVMU9HRmtOakZpTVEiLCJraWQiOiJOVEF4Wm1NeE5ETXlaRGczTVRVMVpHTTBNekV6T0RKaFpXSTRORE5sWkRVMU9HRmtOakZpTVEiLCJhbGciOiJSUzI1NiJ9.eyJhdF9oYXNoIjoiSnJaWTlNdFlWRUlJSlV4LUREQm13dyIsInN1YiI6ImFkbWluIiwiYXVkIjpbIm5jemJnNW01eHh0NnRQNFVNWndCNlB0UW9Rb2EiXSwiYXpwIjoibmN6Ymc1bTV4eHQ2dFA0VU1ad0I2UHRRb1FvYSIsImlzcyI6Imh0dHBzOlwvXC9sb2NhbGhvc3Q6OTQ0M1wvb2F1dGgyXC90b2tlbiIsImV4cCI6MTUxMDgzMTAxMCwibm9uY2UiOiJhc2QiLCJpYXQiOjE1MTA4MzEwMDd9.XKV0ioEvflR4MHGthO3cwXwC88msNgqR4l1O83mfhxOMtO1PG3ABWB5E4aFXFpR9t-8zJs09slhLsDTDhmC33KE8Die61UK9_Vb5aNA4XCkawyJt8dCX6clc6UUbTEO5N1ubXA18QFgwAEWpvoTz1hKx8XLnvOSehbdEKsoPunoHDmXpYJe_9hBg5V3kN-VHxdKdGOtl9u-Aml42s5p45cZY0mlFVcKjatBAf7hqWNPlUebyujDWG1Iyk_-AXNQ2wYi0F77uG7_HstP_tp0sOctu0TYCK8bwBTXEJYMPt1CqOqcae05m8N8hb0zs6Yxvyx_udCJPG-8n2zRB-T-kcg”,”token_type”:”Bearer”,”expires_in”:299494}

Decrypted ID_token will look like below.

{
“at_hash”: “JrZY9MtYVEIIJUx-DDBmww”,
“sub”: “admin”,
“aud”: [
“nczbg5m5xxt6tP4UMZwB6PtQoQoa”
],
“azp”: “nczbg5m5xxt6tP4UMZwB6PtQoQoa”,
“iss”: “https://localhost:9443/oauth2/token",
“exp”: 1510831010,
“nonce”: “asd”,
“iat”: 1510831007
}

When two access tokens are issued there are some validations to be done. In this case, one access token is issued from authorization endpoint and the other is issued from the token endpoint. These two access tokens may or may not be the same.

Code ID_Token

In this response type, we request a code and an id_token from the authorization endpoint.

Example of Authorization request

https://localhost:9443/oauth2/authorize?response_type=code id_token&client_id=<Client ID>&nonce=asd&redirect_uri=http://localhost:8080/playground2/oauth2client&scope=openid

Example of a successful Authorization response for the above request.

http://localhost:8080/playground2/oauth2client?code=16fd899f-5f0c-3114-875e-2547b629cd05&id_token=eyJ4NXQiOiJOVEF4Wm1NeE5ETXlaRGczTVRVMVpHTTBNekV6T0RKaFpXSTRORE5sWkRVMU9HRmtOakZpTVEiLCJraWQiOiJOVEF4Wm1NeE5ETXlaRGczTVRVMVpHTTBNekV6T0RKaFpXSTRORE5sWkRVMU9HRmtOakZpTVEiLCJhbGciOiJSUzI1NiJ9.eyJhdF9oYXNoIjoiSnJaWTlNdFlWRUlJSlV4LUREQm13dyIsImNfaGFzaCI6IlM1VU9YUk5OeVlzSTZaMEczeHhkcHciLCJzdWIiOiJhZG1pbiIsImF1ZCI6WyJuY3piZzVtNXh4dDZ0UDRVTVp3QjZQdFFvUW9hIl0sImF6cCI6Im5jemJnNW01eHh0NnRQNFVNWndCNlB0UW9Rb2EiLCJpc3MiOiJodHRwczpcL1wvbG9jYWxob3N0Ojk0NDNcL29hdXRoMlwvdG9rZW4iLCJleHAiOjE1MTA4MzE1MTIsIm5vbmNlIjoiYXNkIiwiaWF0IjoxNTEwODMxNTA4fQ.BsiXZwP_EFnNH-5r01z4P18OZbVY1WHOD1GSTrDa4-TxcSEuMOlvIQA54Poy0hUS8RCP46XB-WhUaOHQpvsHBj6CUCkNWAqJj5F-TetXUhONhnI0Hp7K3zofa_E5-ucFmUoKVwk-wFAMakKziIsX9P8v9-mi2kPlQPDyS3i7tkRlABS5emgbOSHxNsoKjdaglLT78zdARMFfF0i0oaDyRv9nfZIgSZJE1Qec99DA7engA43NJQCB1vMjF9Qruefyyjtq2abaLLRG6Yh6NeWDyIXkjjbHEcKxzBsKU6VqL84DqHHYFUwZ1nL2aLon1kHXUHgGfuhuBJ5qIwEtbZrQLw#session_state=d96bad64e37e82196898a824082aafbdd945c922e7d40cb4e0013d9fad6d68c8.o0_m4GJ1YJvNUUqg8k3LrQ

Decrypted ID_token will look like below.

{
“at_hash”: “JrZY9MtYVEIIJUx-DDBmww”,
c_hash”: “S5UOXRNNyYsI6Z0G3xxdpw”,
“sub”: “admin”,
“aud”: [
“nczbg5m5xxt6tP4UMZwB6PtQoQoa”
],
“azp”: “nczbg5m5xxt6tP4UMZwB6PtQoQoa”,
“iss”: “https://localhost:9443/oauth2/token",
“exp”: 1510831512,
“nonce”: “asd”,
“iat”: 1510831508
}

One important thing in this id_token is, it is required to have a c_hash value. So what is c_hash?

c_hash is the base64url encoding of the left-most half of the hash of the octets of the ASCII representation of the code value, where the hash algorithm used is the hash algorithm used in the alg Header Parameter of the ID Token’s JOSE Header.

c_hash value is mandatory when an id_token is issued with code, where the response type is equal to code id_token or code id_token token.

By sending the code to token endpoint we can request for an access token, refresh token and id_token. You can use the same curl command provided in code token. Below is the response from token endpoint.

{“access_token”:”1940a308-d492–3660-a9f8–46723cc582e9",”refresh_token”:”6b96cc3a-00da-3d7d-acd1–5aaf76dcd9d4",”scope”:”openid”,”id_token”:”eyJ4NXQiOiJOVEF4Wm1NeE5ETXlaRGczTVRVMVpHTTBNekV6T0RKaFpXSTRORE5sWkRVMU9HRmtOakZpTVEiLCJraWQiOiJOVEF4Wm1NeE5ETXlaRGczTVRVMVpHTTBNekV6T0RKaFpXSTRORE5sWkRVMU9HRmtOakZpTVEiLCJhbGciOiJSUzI1NiJ9.eyJhdF9oYXNoIjoiSnJaWTlNdFlWRUlJSlV4LUREQm13dyIsInN1YiI6ImFkbWluIiwiYXVkIjpbIm5jemJnNW01eHh0NnRQNFVNWndCNlB0UW9Rb2EiXSwiYXpwIjoibmN6Ymc1bTV4eHQ2dFA0VU1ad0I2UHRRb1FvYSIsImlzcyI6Imh0dHBzOlwvXC9sb2NhbGhvc3Q6OTQ0M1wvb2F1dGgyXC90b2tlbiIsImV4cCI6MTUxMDgzMjI3MSwibm9uY2UiOiJhc2QiLCJpYXQiOjE1MTA4MzIyNjd9.jAGLp8FFdIyFi4ZmvRPX9hVu8NbLVL2iM1895UNrS7wqgl2PCi7zHnvBoOYkbsxxMYGoVepFNzz7hHbk-kuzq_kBoBsZK2Ucbv0hUkwiEkigLy6hpGm-mqXjai3cjlJevWOVcZbMhkEyRlsZtdUG0RCzteT7emAuZLFm5zfMpq1h5JsVRGjK_6fQbHhB2Svkl_kV_ctAD8_kymASGEjRGnwGW5np4uBI0NPYMDTvrl8N9i6yfUVD9-y7rL9Gtrq9hK28Swj5Szvv_c1IX8wYBP-p8gu2cBpGIulIq-OkbfCUh-rrbh96relOaKwKwk0g7nST6o6wZTAwaicNQBYHYw”,”token_type”:”Bearer”,”expires_in”:298234}

Decrypted ID_token will be looked like below.

{
“at_hash”: “JrZY9MtYVEIIJUx-DDBmww”,
“sub”: “admin”,
“aud”: [
“nczbg5m5xxt6tP4UMZwB6PtQoQoa”
],
“azp”: “nczbg5m5xxt6tP4UMZwB6PtQoQoa”,
“iss”: “https://localhost:9443/oauth2/token",
“exp”: 1510832271,
“nonce”: “asd”,
“iat”: 1510832267
}

When two id_tokens are issued there are some validations that must be done. In this case one id_token is issued from authorization endpoint and other one is issued from token endpoint. Below are the validations needed from the specification.

  1. “iss” and “sub” claims values must be identical in two id_tokens.
  2. If either ID Token contains claims about the End-User, any that are present in both should have the same values in both.
  3. All Claims about the Authentication event present in either should be present in both.
  4. The at_hash and c_hash Claims may be omitted from the ID Token returned from the Token Endpoint even when these claims are present in the ID Token returned from the Authorization Endpoint.

Code ID_Token Token

In this response type we request a code, an access token and an id_token from the authorization end point.

Example of Authorization request

https://localhost:9443/oauth2/authorize?response_type=code id_token token&client_id=<Client ID>&nonce=asd&redirect_uri=http://localhost:8080/playground2/oauth2client&scope=openid

Example of a Successful Authorization Response

http://localhost:8080/playground2/oauth2client#access_token=1940a308-d492-3660-a9f8-46723cc582e9&code=55aa698d-ac3b-30ec-b4ca-f5e803590a4b&id_token=eyJ4NXQiOiJOVEF4Wm1NeE5ETXlaRGczTVRVMVpHTTBNekV6T0RKaFpXSTRORE5sWkRVMU9HRmtOakZpTVEiLCJraWQiOiJOVEF4Wm1NeE5ETXlaRGczTVRVMVpHTTBNekV6T0RKaFpXSTRORE5sWkRVMU9HRmtOakZpTVEiLCJhbGciOiJSUzI1NiJ9.eyJhdF9oYXNoIjoiSnJaWTlNdFlWRUlJSlV4LUREQm13dyIsImNfaGFzaCI6IlhDUnVTMmhFT0JfM0hkeG9FM0pxT2ciLCJzdWIiOiJhZG1pbiIsImF1ZCI6WyJuY3piZzVtNXh4dDZ0UDRVTVp3QjZQdFFvUW9hIl0sImF6cCI6Im5jemJnNW01eHh0NnRQNFVNWndCNlB0UW9Rb2EiLCJpc3MiOiJodHRwczpcL1wvbG9jYWxob3N0Ojk0NDNcL29hdXRoMlwvdG9rZW4iLCJleHAiOjE1MTA4MzMxNjQsIm5vbmNlIjoiYXNkIiwiaWF0IjoxNTEwODMzMTYwfQ.WgpDf07dDVqrJRBbe_EqLYAfuRQQ1GkBJzgxaIczLTU_e-HasS6e24l75P0Csv0i2gUXk_H9d8zyJ6zalp2geBUmJ1wXLJtELrp-wvVaHVj-_aLHXM_8bsjL-BTj_f-OUEpGiDsPh19GxcMWw6hOubM0JKMh6ZWbF_A7-7RWwlh3vvRSjHhzhWypfjfP1NGTByjICJWF31AbGgfBy7OUUDhOIURYZM0m5u0fmvvD4O8qah1zjTxUL6mLaalOZ7QNppPU7SmPgeSQnfNsxy5KCA_N1vYyNLxzs3NitcCZAOQ88XU2AF-W4Sykay0tp1qiI35mqHg2cYinNPEdrnCYyQ&token_type=Bearer&expires_in=297341&session_state=872ac70304690624d4b3e2c705b5f452043be5f758ddd2487aa193730d9ef809.IwoAA6ua4m5CRth0erWuxA

Decrypted ID_token will look like below.

{
“at_hash”: “JrZY9MtYVEIIJUx-DDBmww”,
c_hash”: “XCRuS2hEOB_3HdxoE3JqOg”,
“sub”: “admin”,
“aud”: [
“nczbg5m5xxt6tP4UMZwB6PtQoQoa”
],
“azp”: “nczbg5m5xxt6tP4UMZwB6PtQoQoa”,
“iss”: “https://localhost:9443/oauth2/token",
“exp”: 1510833164,
“nonce”: “asd”,
“iat”: 1510833160
}

By sending the code to token endpoint we can request for an access token, refresh token and id_token. You can use the same curl command provided in code token. Below is the response from token endpoint.

{“access_token”:”1940a308-d492–3660-a9f8–46723cc582e9",”refresh_token”:”6b96cc3a-00da-3d7d-acd1–5aaf76dcd9d4",”scope”:”openid”,”id_token”:”eyJ4NXQiOiJOVEF4Wm1NeE5ETXlaRGczTVRVMVpHTTBNekV6T0RKaFpXSTRORE5sWkRVMU9HRmtOakZpTVEiLCJraWQiOiJOVEF4Wm1NeE5ETXlaRGczTVRVMVpHTTBNekV6T0RKaFpXSTRORE5sWkRVMU9HRmtOakZpTVEiLCJhbGciOiJSUzI1NiJ9.eyJhdF9oYXNoIjoiSnJaWTlNdFlWRUlJSlV4LUREQm13dyIsInN1YiI6ImFkbWluIiwiYXVkIjpbIm5jemJnNW01eHh0NnRQNFVNWndCNlB0UW9Rb2EiXSwiYXpwIjoibmN6Ymc1bTV4eHQ2dFA0VU1ad0I2UHRRb1FvYSIsImlzcyI6Imh0dHBzOlwvXC9sb2NhbGhvc3Q6OTQ0M1wvb2F1dGgyXC90b2tlbiIsImV4cCI6MTUxMDgzMzMwNywibm9uY2UiOiJhc2QiLCJpYXQiOjE1MTA4MzMzMDN9.k69ufNIJHJHb6foeRSMVoJsgAWz0q65_8R6Lhz-tIW-tdLDI7eNg3kSL5-S2T3uFn7XFvn113wEWvCS8X3JBCIPMAFCmGBCR_L5pCh_OO6_xQeZyfa0fx_R27kZ9EIW5u0WSSjlpzzvr_50YldCfXMhZASjZlA5sCZ9BReyhkEUW_kSCWUDJEPaFQqgKVNfnRmr1q4N2lJwXPHjjE-4BcTMxKY87mqFzq_HVdXc1SRVIG0iuWkiYaD34pK8ZI12GFGSmOpDzhYb06uxrR8GC4jpq_WHMvMKrPrLaoVkEFaqomgxLIOJaNZJzqpe3wlaWM952eTndpSW0HSR5kgZgmw”,”token_type”:”Bearer”,”expires_in”:297198}

Validations are the same as mentioned in other response types.

I think you got a good understanding of the hybrid flow and how it is working. Thank you for reading.

--

--

Hasini Witharana
Identity Beyond Borders

PhD Candidate @ University of Florida. Security Research Intern @ Intel. Software Engineer @ WSO2.