Open For Ad

Open for Ad

Latest Posts

OpenId Connect(OIDC): OIDC workflows and Internals of ID token generation to authenticate user

OAuth2 was not designed to implement sign-in operations, Most providers only exposed OAuth2 as a way of supporting delegated authorization for their API.
In previous post OAuth 2.0 : How an applicaiton use OAuth to access another application API we established 

  • OAuth2.0 is all about accessing APIs and 
  • access token but does deals with who logged in.
In order to prevent OAuth2.0 abuse in designing sin-in workflows(piggybacked on OAuth2 flows), leading industry came together and decided to introduce a new specification, called OpenID Connect, which formalizes how to layer signing in on top of OAuth2.

  • The OpenID Connect (OIDC) protocol provides an identity service layer on top of OAuth 2.0, designed to allow authorization servers to authenticate users for applications and return the results in a standard way. 
  • OpenID Connect describes how an application can, instead of asking for an access token (or alongside access token) request for an additional entity called ID token.
  • In a tri-party(end-user, application/client and Authentication server[AS]) interaction, its AS which generates ID token to authenticate end-user and consumed by client/application.

OIDC ID Token

  • An ID Token is a security token used by an OpenID Provider to convey claims to an application about an authentication event and authenticated user 
  • An ID token is a  token meant to be consumed by the client itself, as opposed to being used by the client for accessing a resource.
  • ID Tokens are encoded in JSON Web Token(JWT). The JWT format is designed to convey claims between two parties. As a JWT, an ID Token consists of a header, a payload, and a signature. 
  • ID Token payload consist of following details
    issuer(iss) - string representing the source of the token
    audience(aud) - represents the particular application which the token has been issued for,
    issued-at (iat) and expiration (exp) - coordinates that are used for evaluating whether this token is still within its validity .

Before going into details how to generate ID Token, first lets understand real world layered sign-in simulated with OpenID Connect - Access LinkedIn /feeds(https://www.linkedin.com/feed/) end point from Google credentials.

  1. From any browser(Incognito) hit https://www.linkedin.com/feed/. By doing this since we wanted to access protected resource and I am not signed-in, so LinkedIn app prompt to sign-in.

  2. Use Google credential to sign-in LinkedIn app. By doing so in step 2 and 3, once I am authenticated by Google/GMail Authorization server & internally ID token passed from Google Auth Server to LinkedIn.

  3. Once ID token is validated by LinkedIn, https://www.linkedin.com/feed/ is accessible as cookie has been set in background and I am an authenticated user for LinkedIn.

Similar to this we can have access blogger app using google credentials & many more. It can be viewed as delegating authentication to third entity(AS) and application relying on Token generated by AS instead of capturing user-id and password credential.


OIDC workflows and ID_TOKEN Generation Mechanism

The OIDC flows are designed around the constraints of different types of applications and bear some similarity to the grant types defined in OAuth 2.0. The original OIDC core specification defines the following flows:

Authorization Code Flow 

This flow is similar to the OAuth 2.0 authorization code grant in relying upon two requests and an intermediary authorization code.

  • To authenticate a user, an application redirects the user’s browser to an OpenID Provider. The OpenID Provider authenticates the user and redirects the user’s browser back to the application with an authorization code. 
  • The application uses the authorization code to obtain an ID Token, access token from the OpenID Provider’s token endpoint.

Authorization Code Flow ID token generation to authenticate user to allow restricted resource access - Who has Signed in ?

Lets consider 3 three actor entities, we will use thee entities in this section to understand how ID tokens are generated to allow sign-in an app via third party credentials. 

  1. End user(client)
  2. Application(with restricted resource end user want to access) and 
  3. Authorization server(generates ID token)

A prerequisite to run commands to generate ID Token(IDT) is to setup an Authorization server(AS) for "webapp.com". Follow Setup okta auth server and custom scope to setup Authorization server and ready with authorization server client-id and secret.

Follow below steps to understand how ID token is generated and restricted resources access are allowed.
<Diagram>

  1. Request Protected resource on Web App(webapp.com): Browser reaches out to the application to access a protected resource and its not accessible by anonymous requests.

  2. Authorization Request Redirect : Application middle ware controller intercept this request and redirect request to authorization server via client. GET redirect(302) request looks like following:
        https://dev-xxxxxx.okta.com/oauth2/default/v1/authorize?
        response_type=code&
        scope=openid+profile+email&
        client_id={YOUR_CLIENT_ID}&
        state={RANDOM_STRING}&
        redirect_uri=https://example-app.com/redirect&
        code_challenge={CODE_CHALLENGE}&
        code_challenge_method=S256
    

    • Authorization endpoint:   The first element is above redirect request where we expect authorization server to be available with authorization send point.  
    • Response type: The response_type parameter indicates the artifact that we are interested in. In this particular case webapp is interested in sign-in(authentication) so we need an ID token. 
    • Scope: The scope parameter represents the reason for which we are asking for the artifacts.  Here I have specified openid, profile, and email.
      Note: openId scope is enough to get ID Token but we can  add the profile and email scopes to get more information about the user.
    • client_Id: This client_id parameter is the identifier of your application at the authorization server. Copy client Id from Okta account application set up earlier. 
    • state and code_challenge: Create the PKCE Code Verifier CODE_CHALLENGE from https://example-app.com/pkce -
    • redirect_uri: The redirect_uri parameter has a very important role. It represents the address of application which is making request and where we expect tokens and artifacts to be returned.We  need to specify this because the tokens that we use in this context are what we call bearer tokens.

  3. Execute redirection end point:  Run following command in browser(simulate hitting authorization end point). 
        https://dev-71227370.okta.com/oauth2/default/v1/authorize?
        response_type=code&
        scope=openid+profile+email&
        client_id=0oa49rv6d5DV3MMfC5d7&
        state=8142744000&
        redirect_uri=http://localhost:8080/authorization-code/callback&
        code_challenge=3gyPLuzjTU_yEiKKmUfK-qw30KAHJSNB_o7vE9sxZ7k&
        code_challenge_method=S256
    

    Authorization code generation:

    Note: I am already signed-in in Okta account from same browser, that's why Okta Auth server does not enforce for entering login credentials. If you execute above command in incognito window - you will get prompt to sign-in.

  4. Get access token from auth code: If you got an authorization code as shown in above URL, you’re ready to exchange that for an access token.
    Make a POST request to the token endpoint to exchange temporary authorization code for an access token. Generic curl command template:
        curl -X POST https://dev-xxxxxx.okta.com/oauth2/default/v1/token \
        -d grant_type=authorization_code \
        -d redirect_uri=https://example-app.com/redirect \
        -d client_id={YOUR_CLIENT_ID} \
        -d client_secret={YOUR_CLIENT_SECRET} \
        -d code_verifier={YOUR_CODE_VERIFIER} \
        -d code={YOUR_AUTHORIZATION_CODE}
    
    YOUR_CODE_VERIFIER must be in sync with code_challenge value used in step 3. Otherwise POST call execution would throw
    {"error":"invalid_grant","error_description":"PKCE verification failed."}%

  5. Execute POST curl command with token end point, client-Id and secret.
        curl -X POST https://dev-71227370.okta.com/oauth2/default/v1/token \
        -d grant_type=authorization_code \
        -d redirect_uri=http://localhost:8080/authorization-code/callback \
        -d client_id=0oa49rv6d5DV3MMfC5d7 \
        -d client_secret=gd7q2khudlkSht9B8XAhh0nYEmySL_XNZDePDt9K \
        -d code_verifier=34e9a1373cbd077407fc5a8ecf62d47f8acc4a1688ee249631e33677 \
        -d code=QVJxhYl6AQ5H-LFCd0NbtIFGnECUSOrP-rG-j6nwQO4
    

    Response with id_token

    Note: POST call execution response contain access_token and id_token. It's scope (scope=openid+profile+email used while generating auth_code step2) and grant_type=authorization_code in POST call is doing all magic here[instructing Okta Auth Server accordingly to provide required ID).

    We have learnt earlier Id_token is JWT format payload( a Base64 encoded string ) combing three blocks
    • header : algorithm & token type
    • payload :data 
    • verifying signature

    Decode base-64 string
    using https://jwt.io/

  6. Once application has id_token with all relevant details, cookie can be set in client and when client request for restricted resource - access is allowed(as this time user is authenticated). 


Implicit Flow

The implicit flow in OIDC has similarities to the OAuth 2.0 grant type of the same name.

  • An application that only needs to authenticate users and can obtain user information via an ID Token does not need an access token.
  • Implicit flow does simplify workflow with an risk of exposing an access token in a URL fragment which can be leaked via the browser history.

Send GET redirect(302) request from client browser to authorization server indicating  and expect id_token in response and send via form_post to avoid exposure of id_token in URL.
    https://dev-71227370.okta.com/oauth2/default/v1/authorize?
    response_type=id_token& 
    client_id=0oa49rv6d5DV3MMfC5d7& 
    state=8142744000& 
    nonce=345678& 
    scope=openid& 
    response_mode=form_post&
    redirect_uri=http://localhost:8080/authorization-code/callback

Response coming as form_post can be seen in browser console as follows

Note: Instead of response_mode as form_post we can also get id_token as part of callback URL. Remove "response_mode=form_post" from above request and run above command, id_token would come as part of callback URL .

    https://dev-71227370.okta.com/oauth2/default/v1/authorize?
    response_type=id_token& 
    client_id=0oa49rv6d5DV3MMfC5d7& 
    state=8142744000& 
    nonce=345678& 
    scope=openid& 
    redirect_uri=http://localhost:8080/authorization-code/callback

Response with id_token in URL:


Hybrid Flow 

Hybrid Flow includes elements of both the Authorization Code Flow and Implicit Flow.

  • It is designed for applications with both a secure back end and a front end with client-side JavaScript executing in a browser. 
  • The Hybrid Flow enables models such as returning an ID Token and authorization code in a front-channel response to the application front end, leaving the application back end to obtain an access token (and optional refresh token) from the token endpoint using the authorization code.

Reference : Solving Identity Management in Modern Applications by Yvonne Wilson, Abhishek Hingnikar
--------=========--------

No comments