SAML2 vs JWT: Understanding OpenID Connect Part 3

In part 1 and part 2 of Understanding OpenID Connect, core concepts and the first Authentication Flow (Authorization Code Grant Flow) were introduced. In part 3, we look at the remaining Authentication Flows (Implicit Flow and Hybrid Flow) and some other features of the OIDC specification.

Implicit Flow(OIDC v1.0 spec, Section 3.2): This is similar to the Implicit Grant from the OAuth2 spec, but it actually extends the OIDC Authorization Code Flow. It returns the ID Token and Access Token directly to the user agent as part of the authentication response to the Authorization Endpoint. RPs that use the Implicit Flow can only be public clients (there is no client secret).

The return_type query parameter to the Authorization Endpoint can have one of two values: id_token and “id_token token”. The first value corresponds to an end user authentication scenario; the second value supports end user authentication to an RP and the RP accessing a Resource Server.

For the first response_type value (id_token token), the following steps occur.

Implicit Flow with SSO and API Call (response_type = “id_token token”)

Just like the Authorization Code Flow, the end user will launch a browser (or other User Agent) that makes an initial request to an application (Relying Party). The RP intercepts the request and detects that it is not part of an authenticated session; so, the RP responds to the request with an HTTP Redirect to the OP — step (A). The Authentication Request sent to the Authorization Endpoint looks something like the following:

GET /oidc/authorize?
    response_type=id_token%20token
    &client_id=s6BhdRkqt3
    &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
    &scope=openid%20profile
    &state=af0ifjsldkj
    &nonce=n-0S6_WzA2Mj HTTP/1.1 
  Host: server.example.com

The OP will redirect the User Agent to a login workflow that is served by the OP — step (B). The details of how the authentication works are outside the scope of the OIDC spec. The authentication workflow can include the opportunity for the end user to grant consent to the RP to access resources owned by the end user. Following a successful authentication, the OP will send an HTTP Redirect response to return the user to the Authorization Endpoint. The OP will respond with an Authentication Response that looks something like the following — step ©:

HTTP/1.1 302 Found
  Location: https://client.example.org/cb#
    access_token=SlAV32hkKG
    &token_type=bearer
    &id_token=eyJ0 ... NiJ9.eyJ1c ... I6IjIifX0.DeWt4Qu ... ZXso
    &expires_in=3600
    &state=af0ifjsldkj

Unlike the response from the Authorization Code Flow, this response contains both the ID Token and the Access Token. So, the User Agent will be able to see the Access Token and the ID Token — this presents new surface area for potential attacks that doesn’t exist with the first flow we examined. You will also notice that this redirect URL passes the tokens (and other information) in a URI fragment; so, it is necessary for the User Agent (or code running in the browser, Javascript) to parse the URI fragment and extract the tokens to pass them to the Client (see Section 15.5.3 of the OIDC spec for more information).

The User Agent sends the redirected request (with extracted tokens and other information) to the RP (if there is a server-side component). The request will look something like the following (per Section 15.5.3 of the spec):

POST https://client.example.org/cb
    access_token=SlAV32hkKG
    &token_type=bearer
    &id_token=eyJ0 ... NiJ9.eyJ1c ... I6IjIifX0.DeWt4Qu ... ZXso
    &expires_in=3600
    &state=af0ifjsldkj

The RP intercepts the request and extracts the tokens (and other parameters). The RP validates the Authentication Response per the steps outlined in Section 3.2.2.8 of the OIDC spec (including the ID Token steps described in Section 3.2.2.11 — step (D) — and optionally, though strongly encouraged, the Access Token steps described in Section 3.2.2.9 — step (E)).

Next, if the RP needs additional claims, it can contact the OP’s UserInfo Endpoint to obtain them as described previously — steps (F) & (G). Note, that the RP has the ID Token and it can contain any claim that could be returned by the UserInfo Endpoint. The commentary about this step in the last flow description is also relevant here.

Next, the RP can access the Resource on the Resource Server (let’s call it an API on an API Provider) by making a call to the API with the Access Token in the Authorization header as we have explored before — step (H). The commentary about this part in the Authorization Code Flow section is applicable here.

The Resource Server intercepts the request and extracts the Access Token. The Access Token is validated by the Resource Server — Step (I). The commentary about this part in the Authorization Code Flow section applies here.

Finally, the Resource Server can pass the Access Token it received to the UserInfo Endpoint to obtain an ID Token with the relevant (and allowed) Claims for the end user if needed — steps (J) & (K). Processing of the API request can proceed and a response can be returned to the RP (acting as the API Consumer in this scenario).

The scenario we just walked through is described in the sequence diagram below.

For the second response_type value (id_token), the following steps occur.

Implicit Flow with SSO (response_type = id_token)

Just like the first Implicit Flow, the end user will launch a browser (or other User Agent) that will make an initial request to an application (RP). The RP intercepts the request and detects that it is not part of an authenticated session; so, the RP responds to the request with an HTTP Redirect to the OP’s Authorization Endpoint — step (A). The Authentication Request sent to the Authorization Endpoint looks something like the following:

GET /oidc/authorize?
    response_type=id_token
    &client_id=s6BhdRkqt3
    &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
    &scope=openid%20profile%20email
    &nonce=n-0S6_WzA2Mj
    &state=af0ifjsldkj HTTP/1.1
  Host: server.example.com

The OP will redirect the User Agent to a login workflow that is served by the OP — step (B). As always, details of how the authentication is performed are outside the scope of the OIDC spec. Just like with the other Authentication Flows, the login workflow can include the opportunity for the end user to grant consent to the RP on resources owned by the end user. Following a successful authentication, the OP will send an HTTP Redirect request to return to the Authorization Endpoint. The OP will respond with an Authentication Response that looks something like the following — step ©:

HTTP/1.1 302 Found
  Location: https://client.example.org/cb#
    id_token=eyJ0 ... NiJ9.eyJ1c ... I6IjIifX0.DeWt4Qu ... ZXso
    &state=af0ifjsldkj

This response contains the ID Token. So, the User Agent will be able to see the ID Token — this presents a similar surface area for potential attacks that we saw in the first Implicit Flow scenario. You will, again, notice that this redirect URL passes the ID Token in a URI fragment; so, it is necessary for the User Agent (or code running in the browser, Javascript) to parse the URI fragment and extract the ID Token to pass it to the Client (see Section 15.5.3 of the OIDC spec for more information).

The User Agent sends the redirected request (with extracted ID Token) to the RP (if there is a server-side component). The request will look something like the following (per Section 15.5.3 of the spec):

POST https://client.example.org/cb

    id_token=eyJ0 ... NiJ9.eyJ1c ... I6IjIifX0.DeWt4Qu ... ZXso
    &state=af0ifjsldkj

The RP intercepts the request and extracts the ID Token. The RP validates the Authentication Response per the steps outlined in Section 3.2.2.8 of the OIDC spec (including the ID Token steps described in Section 3.2.2.11 — step (D)).

Next, if the RP needs additional claims, it can contact the OP’s UserInfo Endpoint to obtain them as described previously — steps (E) & (F). The commentary about this step in the last flow description is also relevant here.

These steps are outlined in the sequence diagram below.

Differences

An important difference between the Implicit Flow and the other two flows is that there is no support for authentication of the RP (Client). This is a large contributing factor for its role in native mobile applications and Single Page Application (SPA) use cases.

The Implicit Flow returns tokens from the Token Endpoint to the User Agent as URI fragments of a redirect URI rather than as query parameters.

Another difference is that refresh tokens are not allowed in the Implicit Flow, which is why a refresh token does not appear anywhere in the examples from this section.

Hybrid Flow (OIDC v1.0 spec, Section 3.3): This flow combines aspects of the other two flows. It provides flexibility to allow the front end and back end of an application to receive their own scoped tokens. It isn’t used very often, but is included for completeness.

Rather than go through each of the three possible variations of the Hybrid Flow in the same amount of detail as the Authorization Code Flow and Implicit Flow, let’s use the Authorization Code Grant as a starting point for the Authorization Endpoint interaction. Then, call out the differences between that and the Hybrid Flow — this is how the spec lays it out.

For interaction with the Authorization Endpoint, the following differences exist:

  • The response_type parameter is required to have one of the values described earlier in this article (“code id_token”, “code token”, or “code id_token token”).
  • The Authentication Response is the same as that used in the Implicit Endpoint except for:

access_token: This is the OAuth 2.0 Access Token. This is returned when the response_type value contains “token”. A token_type parameter will also be returned.

id_token: The OIDC ID Token. This is returned when the response_type value contains “id_token”.

code: The OIDC Authorization Code. This is always returned as indicated by all possible return_type values containing “code”.

  • Any errors that occur during the authentication or consent phases are handled in the same manner as the Authorization Code Flow and the “Authorization Server MUST return the error Authorization Response in the fragment component of the Redirection URI, as defined in 4.2.2.1 of OAuth 2.0 [RFC6749] and OAuth 2.0 Multiple Response Type Encoding Practices [OAuth.Responses], unless a different Response Mode was specified.”
  • The RP validates the Authentication Response as outlined in Section 3.3.2.8 of the OIDC Spec.

For the Token Endpoint, interaction will again proceed in the same manner as the Authorization Code Grant Flow (per Section 3.3.3 of the OIDC spec), with the following exceptions:

  • The contents of the ID Token returned from the Token Endpoint are the same as the contents of of the ID Token returned by the Authorization Endpoint.
  • If an ID Token is returned from both endpoints, Section 3.3.3.6 adds additional requirements that must be satisfied.
  • The Token returned from the Token Endpoint must be validated in the same manner as for the Authorization Code Flow.
  • If an Access Token is returned from both endpoints, the tokens can be the same or differ. This could be useful in a situation where security attributes drive what UI elements are displayed.

We are not going to go into further detail regarding this flow here, but if you need further information, most of the details can be inferred from the Authorization Code Grant Flow and Implicit Flow discussions earlier.

Initiating Login From a Third-Party (IdP-Initiated Login)

If you will recall from the earlier SAML2 Use Cases, we discussed Service Provider (SP)-Initiated Login and Identity Provider (IdP)-Initiated Login. All of the Authentication Flows discussed so far represent SP Initiated Logins. Section 4 of the OIDC spec defines how logins can be initiated by an OpenID Provider or another third-party.

For an OP to initiate the login process, a request must be sent to a login initiation endpoint on the RP with the following parameters:

iss: Required. This is the Issuer Identifier for the OP that the RP should send the Authentication Request to.

login_hint: Optional. This is a hint about the name (format/type) that would be entered by the end user. This will allow a login workflow to pre-fill the username.

target_link_uri: Optional. This is the URL that the RP is requested to redirect the user to following successful authentication.

Additional information can be found in the OIDC spec.

At the time of this writing, OIDC IdP-Initiated (OP-Initiated, Third-Party Initiated) Login isn’t that common in the wild, yet. But, as OIDC is more widely adopted, support for more advanced use cases will be needed.

Along similar lines, this functionality can also be used by an RP to support multiple OPs (Identity Providers).

Logout Support

The OIDC Session Management specification defines session management and logout functionality. This spec is optional; so, confirm that the OP and RP support it. This post will not go into any further information about OIDC logout.

Summary

This concludes our discussion of OIDC.

In the next post in this series, we will finally look at the JWT Use Cases using what we’ve learned about JWT, OAuth2, and OIDC in this series.

Leave comments and questions below.