OpenID Connect (OIDC) is an authentication layer built on top of the OAuth 2.0 framework. It is specifically built to address the authentication use case. The major difference is that in addition to access token , the client gets an identity token which the client can use for information pertaining to identity.
The OpenID Connect specification defines a set of standard claims. The set of standard claims include name, email, gender, birth date. It also introduces userinfo endpoint, an API that returns information about the user.
Having a valid id_token means that the user is authenticated. used for token based authentication in which cookies can carry self contained id_token with user information.
You can pass an ID Token around different components of your client (eg in microservices architecture) , and these components can use the ID Token to confirm that the user is authenticated and also to retrieve information about them.
OpenID Connect (OIDC) is used for both pure authentication use cases (only id token is required, access token are not required as 3rd party authorization not there) and (authentication + authorization) use cases .
- Federated identity pattern (the alternative to simple login flow ) , this is authentication use case .
- Only id token is required. 3rd party authorization not there , hence no access token required to carry information about authorizations to 3rd party. The consent screen to get the authorizatinos will not be presented to user .
- Single sign on , this is authentication use case.
- It is also handles the user case where in a 3rd party application wants both authentication and authorization (eg a 3rd party image processing app using google drive to save images may need both identity of user(authentication) and ability to save images in google drive (authorization) . One way to look at it is access to identity data is also authorized to 3rd party.(google in in this example)
- For 3rd party authorization only use case (eg a news service has its own authentication mechanism and wants to post to logged in user's twitter account would only need access token to tweet , (id token not required ) from twitters auth server) . ie the news service does not need identity data from twitter. Access token contains information about what access the user has given to thirdy party. in this example the new service will give access token to twitter with information in access token(self contained) that user has authorized tweeting capability.
Federated identity pattern with OIDC
Federated identity pattern steps
- The login request of user is directed to authorization end point.
- The authorization end point sends authentication form.
- The user fills in user id and password and posts to authorizaiton end point.
- Authorization end point validates the user credentails and on success redirects to webserver with id_token.
- The webserver verfies the token signature and typically sets session cookie for session tracking.
- Note that access token audience is resource server hence access token leaking through browser is very unsafe but that is not the case with id token as id token cannot be used to access resource.
The key advangate is that authentication is no longer inside the application. it is carved out as seprate service. this has multiple advantages. Read more about this pattern in this article Federated identity pattern.
OIDC Single Signon
- Single sign on depends on the SSO cookie set by authentication service.
- Application directs the user to authentication service.
- Authentication service checks if SSO cookie found in the incoming request.
- If SSO cookie is not found
- The auth service sends authentication form.
- The user fills his user id and password.
- Auth service validates the user credentails and on success, redirects to app's webserver with id_token.
- SSO cookie is set in the response redirect.
- If SSO cookie is found
- Authorization end point redirects to webserver with id_token without asking the user to login.
Hence all applications which trust the authserver will be able to do single sign on based on SSO cookie set by authentication server.The presense of the cookie will determine if the user has logged on to the device.
OIDC for authorization and authentication use case for 3rd party apps
The sequence diagram shows the flow for a 3rd party image editing software gaining access to user identity and data on google drive.
Step 1.a (Request to authorization end point,response_type=code id_token and openid in scope)
The OIDC flow begins with the client directing the user to the authorization endpoint . The request parameters are
- client_id The ID of the application that asks for authorization.
- reponse_type : Tells the auth server which grant to execute. The response type can be any combination of code, token, id_token .(id_token is introduced by OIDC)
- response_type=code
- if openid NOT included in scope , (this is simply authorization code flow)
- Both the authorization and token end point are used.
- authorization end point generates auth code
- auth code can be exchanged for access token by providing client secret at token end point
- Both the authorization and token end point are used.
- if openid is included in scope
- authorization end point generates auth code
- auth code can be exchanged for access and id token by providing client secret .
- if openid NOT included in scope , (this is simply authorization code flow)
- response_type=token (this is implicit flow)
- if openid NOT included in scope
- access token is generated by authorization end point.
- token end point is not used.
- Note that implicit flow is dprecated now as access token is exposed through browser history.
- if openid included in scope
- even in this case only access token will be generated by authorization end point.
- in OIDC this response type cannot be used.
- if openid NOT included in scope
- response_type=id_token
- id_token is issued from authorization end point.
- this is implicit flow
- this can be safely used in webapps and spa with back end with response_mode=form_post (for authentication only use case).
- response_type=id_token token
- id_token and token will issued from authorization end point.
- this is implict flow
- response_type=code id_token (this is hybrid flow)
- auth code and id token issued by authorization end point.
- the id_token is espcially safe if response_mode=form_post (spa with back end) which stops front end token exposure .
- access token and id token are issued from token end point.
- auth code and id token issued by authorization end point.
- response_type=code token
- auth code and access token are issued from authorization end point
- access token issued from token end point.
- response_type=code token id_token
- auth code , access token , id token issued from authorization end point.
- access token and id token issued from token end point.
- response_type=code
- redirect_uri The redirect_uri of your app, where authentication responses can be sent and received by your app.
- scope A space-separated list of scopes that you want the user to consent to (hence allowing app to get consent for multiple web APIs ). Note that openid should be inclucded in scope. If openid is not included in scope and if response_type=code then this is oauth 2.0 authorization code flow.
- response_mode Specifies the method that will be used by auth server to send the resulting token back to app.
-
- query
- Query provides the code as a query string parameter on the redirect URI.
- this is the most commonly used by web applications.
- fragment
- Typically used for implicit grant. Fragments are only evaluated locally by your web browser and not included into the request to the host. (where as when your browser gets redirected by a website to a URL with a query parameter, the query string is also part of the request that your browser now sends to the host ).In case of the Implicit Grant, you typically have some Javascript application directly running in your browser. There's no need to pass any authorization code to the host.
- form_post
- 200 OK response is sent by authorization end point with response parameters embedded in an HTML form as hidden parameters.
- After the browser loads the response from auth server , body onload event will trigger a form submit and post all the data to redirect uri.
- If you're requesting just the code, you can use query, fragment, or form_post.
- If you're requesting an ID token using the implicit flow, you can't use query as specified in the OpenID spec.
- implict flow with form_post is used for simplified authentcation only use case where spa has a back end.
- while authoriztion code grant can be used implict flow can be used as
- Authentication cookie is http only cookie which is safe from xss attack.
- The id token is not visible in browser history.(becuase of form post)
- Access token is not required as this is federated authentication use case.
- Read more here https://auth0.com/docs/sessions/cookies/spa-authenticate-with-cookies
- while authoriztion code grant can be used implict flow can be used as
- query
- nonce This parameter is included in the authorization request and included in generated id_token as a claim . (unlike state which comes back in redirect uri) The app can match the nonce value passed in the initial authorization end point and the claim in generated id token to determine if the response is correspodning to request ,thus mitigating token replay attack. The generated nonce can be persisted via HttpOnly cookie or via session storage or java script variable . nonce is used to mitigate id_token replay attack in implict and hybrid flows where id token is exposed on front channel. In case of native apps, app memory can be used.
- state
- An opaque value, used for security purposes.(preventing CSRF attack)
- If this request parameter is set in the request, then it is returned to the application as part of the redirect_uri.
- It can be a string of any content that you wish. A randomly generated unique value is typically used for preventing cross-site request forgery attacks.
- the webserver can save the state in a HttpOnly cookie. note that the user is not yet logged in so user's session cannot be used as first party is being used for both authentication and authorization
- for security the cookie should be HttpOnly so that it cannot be used by client side script.
- in case of native apps, state is saved in memory, in case of spa browser memory(via javascript variable) or browser session storage.
- In addtion the value can also encode information about the user's state in the app before the authentication request occurred, such as the page or view they were on.
- It should be noted that the state parameter need not be hashed before making authorization request as it is primarly for defending against XSRF attack where the the attacker does not have access to device.
When the authorization request reaches the authorization server the auth server will
- Ask user/resource owner to provide credentails .
- Show the consent screen to user and ask the user to allow access to 3rd party based on the scope specified in authorization request.
If the user allows then the authorization service will redirect the user to redirect uri with auth code and state
Step 1.b (Response from authorization end point , response_type=code id_token and openid in scope)
On receiving the redirect response the client webserver server will
- Get the auth code in the query string (auth code can only be used once for fetching tokens. This protects against replay of the redirect url)
- Get the state value in query parameter
- Ensure that the state value which is received in the redirect response matches the one saved in cookie, this is done to prevent CSRF attack.
- Note that access token is not there in response hence not shared with browser . This is what makes the authorization code flow secure , the access token will not be visible in browser history.
- The id_token should be verified with the public key of the authserver.
- the nonce value in cookie should be compared with nonce value in id_token to block token replay attack.
- Initiate step 2 (post request to token end point)
Step 2.a (Make POST request to token end point)
The client webserver will typically initiate a POST request to token end point to get access and/or id token with
- client_id The ID of the application that asks for authorization.
- client_secret : Note that client secret is being used in server to server request (also called back channel request)
- code : received in step 1
Step 2.b (The token end point responds with access token and id token)
- Since openid is included in scope then access token and id token will be returned.
- Access token can be opaque or signed jwt token (hence self contained).
- The id token is typically jwt token which can be verified with the public key of the auth server. (since the exchange has happened over back channel verification of id token in this case not critical , if id token was issued by authorization end point then id token verification is required)
Step 3 - client uses access token to interact with resource server.
note that as per the spec
The reason why the spec does not cover how the access token is validated is that the interaction between resource server and authorization server is dependent upon the architecture of the deployment. For instance the authorization service and resource server may the the same or it may be distributed.
Attacks (CSRF/REPLAY)
- auth code injection/CSRF attack. (from a genuine user's device , the user is logged in)
- The CSRF attack can be blocked by
- sending random state parameter as part of intial authorization request.
- the state paramter is stored in user's session/cookie.
- when the response comes back from authorization server the state paramter is present in redirect response.
- the webserver compares the state parameter in response with the state parameter stored in user's session/cookie thus blocking CSRF attack. Read this detailed artcile for a better understanding of CSRF attack. https://clarifyforme.com/posts/5639071388925952/What-kind-of-CSRF-attack-is-blocked-by-state-parameter-in-OAuth
- The CSRF attack can be blocked by
- Auth code replay attack from attacker's device in case of auth code flow.(response_type is code and id token is obtained from token end point)
- state paramter allows request response corrleation check and will block auth code replay attack.
- nonce can block auth code replay attack
- The attacker gets access to authcode via shoulder surfing or he may have access to mobile device of a user, where as user has authenticated from desktop browser. The user's browser history across device can get synched up. Ie in both cases the auth code is leaked as present in front channel/ browser.
- The attacker pastes the redirect response url (with auth code) on his browser.
- If auth code can only once be exchanged with access tokens (most auth servers follow this) then replay attack will fail.
- If the auth server does not stop use of auth code twice even then the replay attack will fail because of nonce. The nonce is stored in HttpOnly cookie on the genuine user's browser .The auth code will be exchanged for access and id token. The nonce value in cookie is compared with nonce claim in id token to correlate the request and responose which will fail on attackers device as cookie will not be present on attacker's device.
- token injection(on genuine user's device) - the request and token response correlation which nonce ensures will block token injection attack.
- Token replay attack from attacker's device in case of implicit(response_type=id_token) /hybrid flow (response_type=id_token code). So id_token will be generated by authorization server and will be part of redirect response url.
- Note that in auth code flow and auth code flow with pkce, token is not exposed to front channel so token replay attack because of say shoulder surfing is not possible.
- In case of web app response_method=form_post, id_token replay attack is allready mitigated as id_token generated by authorization end point not exposed to front channel.
- In case of spa using auth code flow with pkce and response_mode=fragment ,id_token generated by authorization end poin is exposed via front channel and token replay attack can happen.
- The attacker gets access to id_token via shoulder surfing or he may have access to mobile device of a user, where as user has authenticated from desktop browser. The user's browser history across device can get synched up.Ie in both cases the id token is leaked as present in front channel/ browser.
- The attacker pastes the redirect response url (with id token) on his browser
- The nonce value stored in session storage/javascript variable is compared with nonce claim in id token to prevent token replay attack.On the attackers device comparison will fail and request and response correlation will break.
- note that nonce mechanism of request response correlation is very similar to state. nonce is specically added by oidc for token replay/injection attack in case of implict or hybrid flows where the token gets exposed on front channel. state is focussed on auth code injection via csrf / auth code replay.
- note that this flow is not safe(even though token replay blocked) as id_token exposed via front channel ,ie "token exposure" and use by malicious app is a risk eg, In case of native app , malicious native app on attackers device will simply try to use the id token without doing any nonce comparison.The genunine native app cannot be fooled in replay attack of id token as it will do nonce comparsion(the native app would be storing nonce is app memory) and nonce will not exist on attackers genuine app. so even though token replay attack is blocked, the hybrid flow in native app is not safe. In general in implicit/hybrid flow token exposure / interception by malicious client is always a risk as opposed to authorization code flow , where the exposed code is useless without client secret.
OpenID Connect Discovery
OpenID Connect defines a discovery mechanism, called OpenID Connect Discovery. OpenID Connect describes a metadata document (RFC) that contains most of the information required for an application to do sign in. This includes information such as the OpenID/OAuth endpoints to use and the location of the service's public keys. This document can be found by appending the discovery document path to the well known URL: