Beta

Create a tenant

A new tenant starts with its own users, OAuth settings, audit history and logs. You are its first Tenant Admin.

BTL Admin

OPENID CONNECT · LAB

Configure lab-collage from the issuer alone, and follow a moved endpoint

Derive every endpoint from one issuer value, check the discovery document the way the lesson requires, and watch a discovered configuration follow an endpoint move that breaks a hard-coded one.

Partly readyUses both lab tenants

The lesson

Builds on: When validation fails.

New to the labs? Start with the lab toolkit and the shared cast and names every lab uses.

Partly ready. Most of this lab runs today. Steps that wait on platform features are marked, and Missing infrastructure says what they need.

Needs a second tenant. This lab also uses Lab Mail, a second tenant. Additional tenants currently need a paid subscription or a BTL grant, so you may not be able to do the Lab Mail steps yet (gap G66).

Your progress

Press Start before you begin. Only events your tenant records after that count, in the order below. Checking reads your tenant's Audit, so you need Audit read access in it.

  1. Sign in with endpoints taken from discovery

    Recorded as oauth.token succeeded for lab-collage about [email protected].

  2. Move the UserInfo endpoint in Metadata Management

    Recorded as tenant.oauth.metadata.update succeeded.

  3. Call UserInfo at its rediscovered address

    Recorded as oidc.userinfo succeeded (userinfo_served) for lab-collage.

  4. Move the UserInfo endpoint back

    Recorded as tenant.oauth.metadata.update succeeded.

Request console

Requests in this lab can be sent from this page to your tenant: open one and choose Send. Fill in the values below first. They stay in this page's memory and are gone when you leave; secrets are never stored or sent anywhere except the request you send.

Setup

  1. You need lab-collage, Ava, Lab Mail with ISSUER2, and EXPECTED_AUD, ID_ALGS and JWKS_CACHE from the Validation labs. Keep btl-lab callback running.

  2. Write your relying party's discovery step. It takes the issuer from your own configuration, fetches the document, refuses it unless it names exactly that issuer and has the required entries, and only then exports the endpoints:

rp_discover() {
  local doc; doc=$(curl -sf "${1%/}/.well-known/openid-configuration") || { echo "REJECT: discovery fetch failed"; return 1; }
  [ "$(jq -r .issuer <<<"$doc")" = "$1" ] || { echo "REJECT: document issuer does not match $1"; return 1; }
  for f in authorization_endpoint token_endpoint jwks_uri; do [ -n "$(jq -r ".$f // empty" <<<"$doc")" ] || { echo "REJECT: missing $f"; return 1; }; done
  export EXPECTED_ISSUER="$1" AUTHORIZATION_ENDPOINT=$(jq -r .authorization_endpoint <<<"$doc") TOKEN_ENDPOINT=$(jq -r .token_endpoint <<<"$doc") \
    JWKS_URI=$(jq -r .jwks_uri <<<"$doc") USERINFO_ENDPOINT=$(jq -r '.userinfo_endpoint // empty' <<<"$doc") REVOCATION_ENDPOINT=$(jq -r '.revocation_endpoint // empty' <<<"$doc")
  echo "discovered $1"
}
  1. Redefine the track's helpers so they use the discovered endpoints instead of fixed paths:

signin_url() { eval "$(btl-lab pkce)"; eval "$(btl-lab state)"; echo "$AUTHORIZATION_ENDPOINT?response_type=code&client_id=$CLIENT_ID&redirect_uri=http%3A%2F%2F127.0.0.1%3A8765%2Fcallback&scope=$1&state=$STATE&nonce=$NONCE&code_challenge=$CHALLENGE&code_challenge_method=S256$2"; }
exchange() { RESP=$(curl -s -u "$CLIENT_ID:$CLIENT_SECRET" "$TOKEN_ENDPOINT" -d grant_type=authorization_code --data-urlencode "code=$1" --data-urlencode "redirect_uri=http://127.0.0.1:8765/callback" --data-urlencode "code_verifier=$VERIFIER"); TOKEN=$(jq -r '.access_token // empty' <<<"$RESP"); ID_TOKEN=$(jq -r '.id_token // empty' <<<"$RESP"); jq '{token_type, expires_in, scope, error}' <<<"$RESP"; }
  1. In Lab Photos, press Start.

Walkthrough

  1. Fetch the document by hand, built from the issuer plus /.well-known/openid-configuration:

GET$ISSUER/.well-known/openid-configuration Open in console
GET $ISSUER/.well-known/openid-configuration HTTP/1.1
Accept: application/json

Note the status, Content-Type and any Cache-Control header, then read the entries this lesson needs: issuer, authorization_endpoint, token_endpoint, userinfo_endpoint, jwks_uri and id_token_signing_alg_values_supported. For a quick summary of the document and the key set together, run btl-lab discover "$ISSUER".

Why it matters: every address you have used in this track is published here, found from one value.

  1. Run rp_discover "$ISSUER" and print the exported variables. Run a complete sign-in with the redefined helpers (signin_url 'openid%20profile', then exchange), and validate the token with --issuer "$EXPECTED_ISSUER". Everything works unchanged, now driven by discovery.

  1. One value, three places. Compare $EXPECTED_ISSUER, the document's issuer and the iss in your new ID token. All three are identical, character for character.

  1. Move an endpoint. In Lab Photos, open Metadata Management and change the UserInfo path from /oidc/userinfo to /oidc/me. Then call it both ways:

curl -si "$ISSUER/oidc/userinfo" -H "Authorization: Bearer $TOKEN" | head -1
rp_discover "$ISSUER"; curl -s "$USERINFO_ENDPOINT" -H "Authorization: Bearer $TOKEN" | jq .sub

The hard-coded address now gets 404. The rediscovered endpoint returns Ava's sub.

Why it matters: a relying party that copied values from documentation breaks when the provider changes. One that refreshes discovery, checking every refreshed copy the same way, follows the change.

Restore: in Metadata Management, set the UserInfo path back to /oidc/userinfo, then run rp_discover "$ISSUER" again.

  1. Where trust starts. Write your list of configured providers, with short names you chose:

jq -n --arg p "$ISSUER" --arg m "$ISSUER2" '{photos: $p, mail: $m}' > providers.json

Your sign-in button sends photos or mail, and the relying party looks the issuer up here. Nothing in a request, a callback or a token chooses the issuer.

Break it

  1. A document from the wrong address. A setup guide gives you the Lab Mail document's address while your configured issuer is Lab Photos. Check it with your expectation unchanged:

[ "$(curl -s "$ISSUER2/.well-known/openid-configuration" | jq -r .issuer)" = "$ISSUER" ] || echo "REJECT: document names another issuer"

The document is genuine but names a different issuer, so the whole document is discarded.

  1. A trailing slash. Run rp_discover "$ISSUER/". It builds the right address, because it strips the slash, and then refuses the document: document issuer does not match. An issuer is compared exactly.

  1. Taking the expected issuer from the document. Imagine rp_discover had exported whatever issuer the fetched document named. Point it, in your head, at the Lab Mail address from Break it 1: the expected issuer, the key set and every endpoint would all be Lab Mail's, and the Lab Mail token you kept in the previous lab would pass every check up to the audience. Write down which line of rp_discover prevents that.

Check your work

Press Check my progress in Lab Photos. It looks for, in order: a lab-collage token request using discovered endpoints, tenant.oauth.metadata.update for the move, oidc.userinfo with userinfo_served at the moved address, and tenant.oauth.metadata.update for the restore.

The 404 from the old address does not reach Audit, because no endpoint answered there. In Logs you find the discovery document requests for both tenants as oidc.discovery.

Cleanup

Confirm that the UserInfo path in Lab Photos is /oidc/userinfo, then run rp_discover "$ISSUER" so the exported variables point at Lab Photos. Keep providers.json, rp_discover and the redefined helpers for the next labs.

Missing infrastructure

  • G66 Second lab tenant: this lab uses Lab Mail, a second tenant. Additional tenants currently need a paid subscription or a BTL grant, so an ordinary learner can do only the Lab Photos steps until every learner can have a second lab tenant.

Back to all labs

We value your privacy

We use cookies and similar technologies to enhance your browsing experience, and analytics to understand our traffic. By clicking "Allow All", you consent to optional analytics. Cookie Policy

The Lab