Using the OAuth2 / OIDC workflow

The OAuth2 / OIDC workflow lets you run every OAuth 2.0 authorization grant and every OpenID Connect authentication flow against a real authorization server, one step at a time. At each step you see the request before it is sent and the response after it comes back.

These pages show how to use it:

This page covers the parts every grant and flow have in common. Read it first.

The screenshots come from the test suite. Each one was taken by the Selenium job that drives that grant or flow (see Regenerating the screenshots). The authorization server in them is the project’s mock STS (rcbj/iya-sts), running at https://localhost:8081. It is the same server the test suite uses, and it signs anybody in with any password, so you can repeat every step here exactly. To follow along against your own identity provider, use its discovery URL, client IDs and secrets in place of the ones shown.

Before you start

Start the debugger

From a checkout, follow Getting Started in the repository’s README. In short:

git submodule update --init --recursive
./generate-tls-cert.sh
CONFIG_FILE=./env/local.js docker-compose up

Then open https://localhost:3000 and pick the OAuth2 / OIDC card. You can also use the deployed copy at idptools.com. It has no back end, so token requests must be sent from the browser (see Front end or back end).

Register a client at your identity provider

The debugger is a client. Your identity provider must know about it first. Register a client with:

Setting Value
Redirect URI https://localhost:3000/callback (or your debugger’s address + /callback)
Grant types / response types the ones you plan to test
Client type public (no secret) for browser-style tests, confidential (with a secret) for server-style tests
Web origins / CORS the debugger’s origin, if token requests will be sent from the browser

For the mock STS, see Configuring OAuth 2.0 grants and Configuring OpenID Connect flows. In development mode it accepts a client it has never seen. The Device Authorization grant is the exception: that client must be registered first.

How the workflow is laid out

The workflow is two pages.

Page What you do there
Step 1 (oauth2_oidc_1.html) Load the provider’s metadata, choose a grant or flow, and send the authorization request (or the device authorization request).
Step 2 (oauth2_oidc_2.html) See what the authorization endpoint returned, send the token request, and work with the tokens: refresh, introspect, revoke, exchange, call UserInfo, or log out.

Grants that have no authorization request (Client Credentials and Resource Owner Password Credentials) take you straight to step 2 when you choose them.

Every section of both pages is a pane you can collapse or expand by clicking its title. The pages remember which panes you had open.

Step 1: load the provider’s metadata

Every grant and flow starts the same way. In Metadata Retrieval:

  1. Choose the Metadata Source:
    • OIDC Discovery 1.0 for a URL ending in /.well-known/openid-configuration.
    • OAuth 2.0 Authorization Server Metadata (RFC 8414) for a URL ending in /.well-known/oauth-authorization-server.
  2. Enter the Metadata Endpoint URL, for example https://localhost:8081/.well-known/openid-configuration.
  3. Click Retrieve. The document is shown as a table, one row per member.
  4. Click Populate Meta Data below the table. This copies the endpoints and the advertised capabilities into the Configuration Parameters pane.

Metadata Retrieval pane after Retrieve, showing the provider's discovery document as a table

If you have no metadata document, skip this step and type the endpoints into the Configuration Parameters pane yourself.

Step 1: check the configuration

The Configuration Parameters pane holds the settings shared by every request:

Configuration Parameters pane with the Authorization Grant selector, the endpoints filled in from discovery, and the switches at the bottom

Field What it does
RFC 9700 compliance mode Makes the debugger refuse to send anything the OAuth 2.0 Security Best Current Practice forbids. Off by default, so you can test providers that do not comply. See RFC 9700 compliance mode.
Authorization Grant Chooses the grant or flow. The rest of both pages changes to match it.
Endpoints Authorization, token, introspection, revocation, registration, UserInfo and JWKS. Filled in by Populate Meta Data.
Provider metadata The rest of the discovery document, for reference.
Display OIDC Related Artifacts? Shows or hides the ID token, nonce and UserInfo controls.
SSL Certificate Validation Set to No when the provider uses a self-signed certificate and token requests go through the back end.
Use Refresh Token Shows the refresh pane on step 2.
Use PKCE Adds a PKCE code_challenge (RFC 7636) to the authorization request and the code_verifier to the token request.

Step 2: send the token request

Each grant has a token request pane on step 2. Its title depends on the grant, for example Exchange Authorization Code for Access Token. These fields work the same way in every grant:

Field What it does
Client ID / Client Secret The client’s credentials. Leave the secret empty for a public client.
Auth Style POST sends client_id and client_secret in the form body (client_secret_post). Header sends them as HTTP Basic authentication (client_secret_basic).
Initiate Token Endpoint Call From front or backend See Front end or back end.
DPoP (RFC 9449) Binds the access token to a key held by the page. See DPoP.
Add Resource field? Adds an RFC 8707 resource parameter.
Custom query parameters Adds parameters the provider needs that the form does not have a field for.
Request The exact request that Get Token will send. It updates as you type.

Every pane that sends a request has two tabs. Parameters is the form. HTTP shows the request and response exactly as they were exchanged, with headers and timing, once the call has been made. The tab title shows the status code, for example HTTP · 200.

Front end or back end

A token request can be sent two ways:

Step 2: read the results

Results appear in panes below the token request:

Pane What it shows
Authorization Endpoint Results Tokens that came back on the redirect from the authorization endpoint. Only the Implicit and Hybrid flows return tokens there.
Token Endpoint Results The most recent tokens from the token endpoint.
Token Endpoint Results for Refresh Token Call The tokens from the most recent refresh, shown beside the originals so you can compare them.
Token History Every set of tokens this page has obtained. Click one to show it in Currently Viewing.

Each token comes with buttons and links:

After the flow

Further down step 2 are panes that work with the tokens you now hold:

What the debugger remembers

Everything you type is saved in the browser’s localStorage, so the forms are filled in again next time. Passwords are never saved. To start over, click Clear Storage in the Metadata Retrieval pane or clear the site data for the debugger in your browser.

Regenerating the screenshots

The screenshots are taken by the test jobs that drive these screens. The helper that takes them, tests/doc_screenshots.js, does nothing unless DOC_SCREENSHOT_DIR is set. To regenerate them, start the stack, then run each job with that variable set:

cd tests
DOC_SCREENSHOT_DIR=../docs/oauth2-oidc/images \
  CONFIG_FILE=./env/local.js \
  OIDC_FLOW=oidc_hybrid_code_id_token OIDC_DPOP=off \
  node oidc_flows.js -u https://localhost:3000

Each run writes <grant-or-flow>-<step>.png, and overwrites the previous copy.

Job Pictures
oauth2_authorization_code.js oauth2-authorization-code-*
oauth2_implicit.js oauth2-implicit-*
oauth2_resource_owner_password_credentials_grant.js oauth2-password-*
oauth2_client_credentials.js oauth2-client-credentials-*
oauth2_device_authorization.js oauth2-device-authorization-*
oauth2_auth_style.js oauth2-refresh-token-*
oauth2_token_exchange.js oauth2-token-exchange-*
oidc_flows.js (once per OIDC_FLOW, and with OIDC_DPOP=on) oidc-*

The pictures here were taken against the mock STS, using the environment each job’s entry in tests/run-report.js describes. Three details affect what is captured: