In order for the client to make an OpenID Connect request, it needs to have the following basic OAuth 2.0 information about the OpenID Provider and the client:
- end-user authorization endpoint – The authorization server’s HTTP endpoint capable of authenticating the end-user and obtaining authorization.
- jwks_uri – The JSON Web Key URI from which one can fetch the public key of the provider. This is used in lieu of client_secret as it is a public client which does not have a client secret.
- client identifier – A unique identifier issued to the client (RP) to identify itself to the authorization server.
- redirect URI – A URI which was registered as the URI to which the user agent should be redirected after user authentication and authorization.
[scope and other parameters]
- scope – A list of scopes you are going to ask for. One of them has to be 'openid'
- response_type – the response type you want
You can find these from developer documentation or through the optional discovery process. In this document, we will assume that you have gotten them out of band with the following values:
[scope and other params]
Make 'state' and 'nonce', and store it in the session
To prevent XSRF, you have to first create 'state', which is an OAuth 2.0 request parameter. It has to be a cryptographic safe random string so that it is extremely difficult for the attacker to guess.
Feel too complicated? You do not have to do them manually if you use a library like openidconnect.js. If you use such a library, everything comes free.
Create Login link
Using the above parameters and state value, create the login link as:
Redirect the user to the login_link
Once you have created the login link, have the user click the link or otherwise take the user to the link.
Receive the callback and verify
After the user authenticates and authorizes, the response comes back to the Redirect URI. You need to evaluate it. We have been hand coding everything till here, but the evaluation of the response in a public client actually requires some asymmetric cryptography unlike in the case of a confidential client. You probably do not want to write it yourself. It is probably better to use a library. Here, I am using openidconnect.js.
These functions returns the valid ID Token, Code, and Access Token. If the validation fails, it will throw errors. Now that you have an ID Token, you can decode the payload and extract various claims from it as well.
NOTE: getValidIdToken is doing bunch of ID Token checking. Below is the checks that it is performing.
- The value of the state parameter is the same as the one stored in the session.
- The signature on the ID Token is valid and from the expected source.
- Check that the ID Token is issued before the time of checking.
- Check that the ID Token's expiry date is in the future.
- Check that the 'aud' claim value (audience) and its client_id matches.
- Check that the issuer of the ID Token is the one in the server configuration.
- Check that the nonce is equal to that was stored in the session.
Getting claims (attributes) out of ID Token
ID Token can have claims/attributes inside itself. In this example, we have asked email and phone number to be included in the ID Token, so if the server provides it, we can get them from it.
To do so, you need to parse the ID Token. 'openidconnect.js' provides a utility function for it.
Associate the local account with the iss/sub pair
With a valid ID Token, you know who is the user. In many cases, you need to associate it with the local account.
If you look up the iss/sub pair and you do not find it in an existing account, it is either a new user or an existing user whose account is not associated with this OpenID Identifier.
You have several options here.
- Ask the user to login with a local account as well so that you can associate the local account and the OpenID Identifier
- Use the email claim and use it to associate with the local account. You need to send a confirmation email to the user for the linkage though and should not fully log in the user until it is confirmed unless you are sure that the email in your local account is fresh and the server's verified email is correct.
- Create a new account using the OpenID identifier and link them later.
If you look up the iss/sub pair and find one in the local account, you are all set.
(Optional) Getting other claims from Userinfo Endpoint
Userinfo Endpoint is the server endpoint that serves the information related to the user. The response is somewhat similar to the payload of the ID Token but it does not include the authentication event data. Unlike ID Token, which is typically supposed to be small, the Userinfo response can be big and include many things including photo etc.
[TODO] Fill in the details.