From OpenID Connect in Action by Prabath Siriwardena

In this part, we’ll take you through how the authorization code flow works with a SPA in detail.


Take 40% off OpenID Connect in Action by entering fccsiriwardena2 into the discount code box at checkout at manning.com.


How does authorization code flow work?

There are many similarities in the parameters passed in the authentication request and authentication response, like under the implicit flow (discussed in part 1). So, we assume you have gone through part 1 already. The sequence of events or steps that happens during this flow, as well as the messages being passed in each step, are clearly defined in the OpenID Connect specification.

The flow of events in the authorization code authentication flow

Figure 1 lists the sequence of events happens between the OpenID provider, the client application, and the user. The client application in figure 1 can be any type of an application, but here our discussion mostly focuses on a SPA. Over the time, the authorization code flow has become more popular for implementing login with OpenID Connect for SPAs. In the following sections we discuss what happens in each step in the figure 1 in detail.


Figure 1: The client application uses authorization code authentication flow to communicate with the OpenID provider to authenticate the user.


The client application initiates a login request via the browser (step 1)

In the step 1 of figure 1, the client application initiates a login request via the browser. In case of a SPA, we can expect the user clicks on a login link on the web page of the client application, and browser does an HTTP GET to the authorize endpoint of the OpenID provider. Listing 1 shows an example of an authentication request under the authorization code authentication flow.

Listing 1: Authentication request generated by the client application (authorization code flow)

 
 https://accounts.google.com/o/oauth2/v2/auth? 
       response_type=code& 
       client_id=424911365001.apps.googleusercontent.com& 
       scope=openid email& 
       redirect_uri=https%3A//app.example.com/redirect_uri& 
       state=Xd2u73hgj59435& 
       login_hint[email protected]& 
       nonce=0394852-3190485-2490358 
  

In part 1 we discussed the usage of all the parameters in the listing 1, so we do not intend to duplicate the same here. However, a few parameters need attention:

  • response_type: The value of the response_type parameter in the authentication request defines which tokens the authorization endpoint of the OpenID provider should return back to the client application.

In the authorization code flow there is only one possible value: code. The client application expects that authorization endpoint of the OpenID provider to return a code in the authentication response. This is the key parameter in the authentication request that differentiates an authorization code flow from the implicit flow.

  • response_mode: The value of the response_mode parameter in the authentication request defines how the client application expects the response from the OpenID provider. For the authorization code flow, the default value of response_mode parameter is query. So, the client application expects the OpenID provider to return the code and the corresponding parameters in query string to the redirect_uri.

The OpenID provider validates the authentication request and redirects the user back to the browser for authentication (step 2)

Once the OpenID provider validates the authentication request from the client application, it checks whether the user has a valid login session under the OpenID provider’s domain. If the user has logged into the OpenID provider already from the same web browser, then there exists a valid login session, unless its expired.

If the user does not have a valid login session, then the OpenID provider will challenge the user to authenticate (step 2 in figure 2); and also will get user’s consent to share the requested claims with the client application. In step 3 of figure 2 user types the login credentials and in step 4 in figure 2, the browser posts the credentials to the OpenID provider. The steps 2, 3 and 4 are outside the scope of the OpenID Connect specification and up to the OpenID providers to implement in the way they prefer.


Figure 2: The client application uses authorization code authentication flow to communicate with the OpenID provider to authenticate the user.


The OpenID provider returns back the authorization code to the client application (step 5)

In step 5 of figure 2, the OpenID provider returns the authorization code along with the state parameter to the client application in a query string to the redirect_uri (as shown in the following line of code). Once the client application receives the request, it needs to make sure that the value of the state parameter in the response exactly matches the value of the state parameter in the authentication request.

https://app.example.com/redirect_uri?code=YDed2u73hXcr783d&state=Xd2u73hgj59435

The client application exchanges the authorization code to an ID token and an access token (step 6)

Unlike in the implicit flow, in the authorization code flow, the client application does not get the ID token or the access token in the authentication response. To get an ID token and an access token, the client application has to talk to the token endpoint of the OpenID providers, as shown in the step 6 of figure 2. Following listing shows an example request to the token endpoint of the OpenID provider, which carries the authorization code from the authentication response. The token request defined in the authorization code authentication flow in OpenID Connect is identical to the token request defined under the authorization code grant type in OAuth 2.0 specification.

Listing 2: Request to the token endpoint of the OpenID provider (authorization code flow)

 
 POST /token
 HTTP/1.1
 Host: oauth2.googleapis.com
 Content-Type: application/x-www-form-urlencoded
  
 code=YDed2u73hXcr783d&
 client_id=your_client_id&
 redirect_uri=https%3A//oauth2.example.com/code&
 grant_type=authorization_code
  

One key thing to notice here is, in the token request in listing 2, the client application does not authenticate to the OpenID provider. So, we only use the client_id in the request and the client application does not need to have a client_secret or any other authentication mechanism. An SPA is called a public client under the OAuth 2.0 specification and a public client does not have the capability protect any secrets.

Since a SPA runs the browser, it can’t hide any secrets from the end user. Anything that you hide on the browser is visible to the end user. So, no point of having any credentials for an SPA.

The OpenID provider returns back an ID token and access token to the client application (step 7)

In step 7 of figure 2 the OpenID provider returns back an ID token and an access token to the client application, as shown in the following listing.

Listing 3: The response from the token endpoint of the OpenID provider

 
 {
   "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
   "expires_in": 3920,
   "token_type": "Bearer",
   "id_token": "<ID_TOKEN>"
   "refresh_token": "<ACCESS_TOKEN>"
 }
  

The only difference you see in the response in listing 3 and the response you get from the token endpoint under the OAuth 2.0 authorization grant type, here we have an additional parameter called id_token, which carries the ID token. Also, unlike in the implicit flow, in the authorization code flow, the client application also gets a refresh_token, which can be used to renew the access_token and also the id_token.

That’s all for this article. If you want to learn more about the book, check it out on our browser-based liveBook platform here.