OpenID Connect Hybrid Flow
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.
- response type = code token
- response type = code id_token
- 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
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.
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 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.
- “iss” and “sub” claims values must be identical in two id_tokens.
- If either ID Token contains claims about the End-User, any that are present in both should have the same values in both.
- All Claims about the Authentication event present in either should be present in both.
- 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
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.