/dev/posts/

OAuth 2.x and OpenID Connect sequence diagrams

Published:

Updated:

Some sequence diagrams about OAuth 2.x and OpenID Connect.

Some sequence diagrams of OAuth 2.X and OpenID Connect. They provide an overview/summary/roadmap of several OAuth and OpenID Connect (OIDC) specifications. Look at the specifications and other references for details.

Table of content

OAuth

OAuth component diagram
Oauth Flows
Grant (Flow) Initial Request
Authorization Code Grant frontchannel GET/POST authorization_endpoint (response_type=code)
Implicit Grant frontchannel GET/POST authorization_endpoint (response_type=token)
Device Authorization Grant backchannel POST device_authorization_endpoint
Client Credential Grant backchannel POST token_endpoint (grant_type=client_credentials)
Resource Owner Password Credentials Grant backchannel POST token_endpoint (grant_type=password)
Assertion Grants backchannel POST token_endpoint (grant_type=some assertion type)
Token Exchange backchannel POST token_endpoint (grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Atoken-exchangehttp://127.0.0.1:4567/)
OAuth 2.0 overview (using the authorization code grant with PKCE)

Main flows

Authorization Code Grant

This is grant is used to let a client application (such as a web application) obtain an authorization (in the form of an access token) on behalf of a user (resource owner). The client application redirects the user to the authorization server frontend (usually in a web application) where the user can authenticate itself and consent to provide the authorization to the client application.

OAuth Authorization Code Grant, simplified diagram

In this diagram, the user and user agent are not represented explicitly.

OAuth Authorization Code Grant

Warning: user-agent for authorization server frontend code

Native client applications, should use an external user-agent for the authorization server frontend code i.e. either a standalone browser or an in-app browser tab. (such as Android Custom Tab, iOS ASWebAuthenticationSession or cordova-plugin-browsertab).

It should not use an embedded / in-app browser to execute the authorization server frontend logic (WebView, Cordova InAppBrowser).

In-app browser executes the authorization server frontend code in the system/user browser while the in-app browser tab executes the authorization server frontend code in the client application. In the first case, the user credentials are isolated from the client application.

Some extensions (which are represented in the diagram):

Client Credentials Grant

The Client Credentials Grant is used by the client application in order to obtain an access token on its own behalf (not on behalf of a user).

OAuth client credentials grant

Device Authorization Grant

The Device Authorization Grant is used for provisioning an access token (on a user's behalf) to devices which cannot execute a browser or have limited interactivity.

OAuth device authorization grant

Token Usage

Bearer Access Token Usage

Authenticated request with a bearer access token

Refreshing a Token

Refresh tokens are used by the client to obtain fresh access tokens from the authorization server. The idea is to have short-lived (possibly stateless) access token while still allowing for revocation of the authorization. Moreover by forcing the client to make periodical refresh request to the authorization server, the authorization can detect whether a grant is no longer used and revoke it.

Refresh token

Token Revocation

Token Revocation is used by the client application to revoke a token (either a refresh or an access token).

Token Revocation

Token Introspection

Token Introspection is used by the resource server to get information about an (access) token (including whether it is still valid).

Token Introspection

Note: Token introspection on refresh token

The specification allows to use token introspection on the refresh token as well. However, I feel that this is ill defined as the refresh token is expected to be consumed by the authorization server itself.

Note: Token type hint

Moreover the token_type_hint is supposed to be only an hint (and the actual type is not returned by the API). I think this behavior might lead to token confusions vulnerabilities.

OAuth configuration

OAuth Server Metadata

Server Medata is exposed by the Authorization Server to advertize its configuration, its endpoints, etc. See the references for links to real examples of server metadata documents.

Server metadata

OAuth Client Registration

Client registration may be used by the client application for registering itself on the authorization server (and avoiding manual configuration) and for updating its registration.

Dynamic client registration and dynamic client registration management

Authorization request protection

The following approaches may be used (or combined) to protect the privacy and/or integrity of the authorization request.

JWT-Secured Authorization Request

With JWT-Secured Authorization Request (JAR), the authorization request is a JWT which can be signed or signed-then-encrypted.

JWT-Secured Authorization Request (JAR)

Pushed Authorization Requests

With Pushed Authorization Requests (PAR), the client application sends the authorization request directly to the authorization server (backchannel communication) instead of sending it through the user agent (frontchannel communication). This prevents the user from having access to the authorization request and from tampering with it.

Pushed Authorization Requests (PAR)

Bound Tokens

Certificate-Bound Access Tokens

Certificate-Bound Access Tokens are access tokens which can only be used on top of a mTLS connection associated with a given client certificate. This protects against access token leakage. In particular, this makes it possible for the authorization server to safely issue a single access token which can be consumed by several (unrelated, untrusting) resource servers[1].

Client authentication using mutual TLS and Certificate-Bound Access Tokens

Demonstrating Proof-of-Possession

Demonstrating Proof-of-Possession (DPoP) is an alternative to Certificate-bound Access Tokens when mTLS is not practical (eg. for Single Page Applications). The idea is the same but demonstration of the possession of a private key is given at the application (HTTP) layer (in a DPoP HTTP header) instead of the TLS layer.

OAuth 2 Demonstrating Proof-of-Possession at the Application Layer (DPoP)

Advanced Grants

These mechanisms are used for plumbing such as interworking with other authorization/authentication systems.

Assertion Grants

OAuth Assertion Grants diagram

Token Exchange

Token Exchange may be used:

This is a very general framework for exchanging tokens. A lot here is left to interpretation/profiling.

OAuth Token Exchange diagram
Available token types (requested_token_type, subject_token_type and actor_token_type)
Value Semantic
urn:ietf:params:oauth:token-type:access_token (Opaque) Access Token issued by the AS
urn:ietf:params:oauth:token-type:refresh_token (Opaque) Refresh Token issued by the AS
urn:ietf:params:oauth:token-type:id_token OpenID Connect ID Token
urn:ietf:params:oauth:token-type:saml1 SAML1 token (encoded in base64url)
urn:ietf:params:oauth:token-type:saml2 SAML2 token (encoded in base64url)
urn:ietf:params:oauth:token-type:jwt JWT

Some references:

Legacy OAuth Grants

These two grants can be considered as deprecated and is not going to specified in OAuth 2.1.

Implicit Grant

The implicit grant was intended to be used for non-confidential clients. You should not use the authorization code grant with Proof Key for Code Exchange (PKCE) which is more secure.

OAuth implicit grant

Note: lack of support for refresh tokens for some grants

Refresh tokens are NOT supported for the implicit[2] grant and for the client credentials grant.

Resource Owner Password Credentials Grant

In this insecure legacy flow, the user provides his/her password directly to the client application.

OAuth resource owner password credentials grant (aka password grant)

Note: limitations of the resource owner password grant

The password grant is very insecure and limited:

  • The user password is given to the OAuth client (which could use it for whatever). This kind of defeats the purpose of OAuth which is to avoid giving your credentials to the client application in the first place.
  • It only support password-based authentication (no MFA, WebAuthn, passkeys, etc.).
  • There is no provision for for checking the user consent and the user cannot check which authorizations are being requested.

OAuth Discovery (drafts)

OAuth Authorization Server Discovery

Authorization Server Discovery (draft) let the client application discover the authorization server to be used for a resource server.

Authorization server discovery (draft)

Warning: Access Token exfiltration

Using this mechanism, a malicious server could pretend to be a resource server for https://as. A client could initiate an OAuth flow with the authorizaton server, obtain an access token to the malicious server. This malicious server could then use this access token. I therefore think that additional mechanisms are needed to make this work safely.

OAuth Client Discovery

Client Discovery (draft) let the authorization server discover the client instead of having the the client register itself.

Client discovery

OpenID Connect

OpenID Connect component diagram
OpenID Connect Flows
Flow response_type nonce c_hash at_hash …:rt_hash
Authorization code flow code OPTIONAL OPTIONAL OPTIONAL N/A
Implicit flow id_token token REQUIRED OPTIONAL REQUIRED N/A
id_token REQUIRED OPTIONAL OPTIONAL N/A
Hybrid flow code id_token REQUIRED REQUIRED[3] REQUIRED[3:1] N/A
code token REQUIRED OPTIONAL OPTIONAL N/A
code id_token token REQUIRED REQUIRED[3:2] REQUIRED[3:3] N/A
CIBA push mode N/A N/A N/A REQUIRED REQUIRED[4]
CIBA other modes N/A N/A N/A OPTIONAL OPTIONAL
OpenID connect overview (using the authorization code flow with PKCE)

Authorization Code Flow

OpenID Connect with the Authorization Code Flow, simplified

In this diagram, the user and user agent are not represented explicitly.

OpenID Connect with the Authorization Code Flow

See Initiating User Registration via OpenID Connect 1.0 for prompt=create which let the Relying Party request a user creation flow.

Token Usage

User Information

In OpenID Connect, the access token can be used to obtain information about the authenticated user using the userinfo_endpoint.

UserInfo

The acces_token may be used by the client to obtain additional user information.

Refreshing a Token

Refresh token

In a refresh token response, an id_token may be returned by the OpenID Provider but this is not required.

Other OpenID Connect Flows

Implicit flow

OpenID Connect implicit flow

Hybrid flow

OpenID Connect hybrid flow.

In this flow, an authorization code is returned in the authentication response alongside with the access_token and or id_token.

Note: at_hash and c_hash claims

The at_hash and c_hash claims contain half of the hash of the access_token and code respectively. The former is required in both implicit and hybrid flows. The latter is required in the ID token returned by the authorization endpoint in the hybrid flow. They protect against access token and authorization code substitution attacks respectively.

OpenID Connect Discovery and Registration

OIDC Discovery is based on Webfinger.

OpenID Connect discovery and client registration

Third-party Inititated Login

In Third-party Inititated Login, the login process is initiated by the OpenID provider or another party.

OpenID Connect Third-party Inititated Login

Session Management

The Session Managerment feature uses a <iframe> for front-channel communication of session state update. The Relying Party includes a iframe of the OpenID Provider. This iframe sends message to its parent (the Relying Party) when it want to signal changes of the session.

OpenID Connect Session Management

Note: two iframes

The specification mentions two iframes. But as far as I understand, the Relying party iframe is not stricly absolutely necessary and is only an implementation detail.

Logout

Front-channel logout

With front-channel logout, the logout process is initiated by the OpenID Provider through the user UA (front-channel request) using a <iframe>.

OpenID Connect Front-Channel Logout

Back-channel logout

With back-channel logout, the logout process is initiated by the OpenID Provider using a direct (back-channel) request.

OpenID Connect Back-Channel Logout

Relying-Party initiated logout

OpenID Connect Relying Party Initiated Logout

CIBA

CIBA component diagram
OpenID Connect Client-Initiated Backchannel Authentication Flow (CIBA)

This is not unlike the device flow but more user friendly.

Note: CIBA without OpenID Connect

You might want to use CIBA in plain OAuth 2 (without OpenID Connect). However, the specification is defined in the context of OpenID Connect and its usage without OpenID Connect it unspecified.

Appendix, Token Summary

Overview of different tokens
Name Flow Content
Authorization code (code) AS → client → AS opaque
Access Token (access_token) AS → client → RS opaque to clients (may be a JWT, at+jwt)
Refresh token (refresh_token) AS → client → AS opaque (sometimes a JWT)
JWT-Secured Authz. Request (JAR) (request) client → AS JWT (oauth-authz-req+jwt)
JWT-Secured Authz. Response Mode (JARM) AS → client JWT
JWT response for Token Introspection AS → RS JWT (token-introspection+jwt)
DPoP Proof-of-possession (DPoP HTTP header) client → AS / RS JWT (dpop+jwt)
Software Statement (software_statement) client vendor → client → AS JWT
Authorization state (state) client → AS → client opaque
Logout state (state) client → AS → client opaque
DPOP Nonce AS → client → AS opaque
RS → client → RS opaque
PKCE Code Verifier (code_verifier) client → AS opaque (random)
PKCE Code Challenge (code_challenge) client → AS hash of the code verifier (base64url)
OIDC ID token (id_token) OP (AS) → client JWT
OIDC Nonce (nonce) client → AS → client opaque
OIDC Session ID (sid) AS → client → AS opaque
OIDC Session State (session_state) OP (AS) → client opaque
OIDC private_key_jwt and client_secret_jwt client authentication (client_assertion) client → OP / AS JWT

Appendix, Client Authentication Methods

Possible client authentication methods (*_auth_methods_supported, etc.) include:

In addition, client assertions can be used for client authentication (client_assertion=...&client_assertion_type=...):

Appendix, Testing OpenID Connect using Keycloak

Keycloak is an Apache-licensed Identity and Access Management (IAM) software. We can quickly spawn a local instance in a container in order to experiment with OAuth and OpenID Connect:

podman run --name keycloak -p 127.0.0.1:8080:8080\
    -e KEYCLOAK_ADMIN=admin \
    -e KEYCLOAK_ADMIN_PASSWORD=change_me \
    quay.io/keycloak/keycloak:20.0.1 start-dev

A different port can be used:

podman run --name keycloak -p 127.0.0.1:3000:3000 \
    -e KEYCLOAK_ADMIN=admin \
    -e KEYCLOAK_ADMIN_PASSWORD=change_me \
    quay.io/keycloak/keycloak:20.0.1 start-dev --hostname-port=3000 --http-port=3000

Some interesting Docker/Podman arguments:

Some interesting KeyCloak arguments:

Interesting endpoints:

The Keycloak web site hosts a simple test OpenID connect client which can be used to test the OIDC provider.

See as well:

References

Relevant IANA registries:

Lists of specifications:

UMA 2.0:

Informational:

Related:

Examples of Server Metadata:

Microsoft Active Directory Federation Service (ADFS):

Keycloak:

Integration with SCIM:

Documentation of some existing implementations and services:

Security:

HEART Working Groupe (health-related):

Other:


  1. Without this, RS1 (resource server 1) could receive an access tokens with "aud":["rs1","rs2"] from the client and use it on RS2. ↩︎

  2. See “Why in implicit grant grant , the auth server MUST NOT issue a refresh token” for why the refresh token is not supported in the implicit grant. ↩︎

  3. The c_hash and at_hash claims are REQUIRED in the id_token returned as part of the authentication response (when the corresponding value is present as well). They are OPTIONAL (when relevant) in the id_token returned in the Access Token Response. ↩︎ ↩︎ ↩︎ ↩︎

  4. If a refresh_token is sent. ↩︎