OPENID CONNECT · LAB
Suggest an account with login_hint, pin it with id_token_hint
Prefill a sign-in with an email hint and sign in as someone else anyway, then use an expired ID token as id_token_hint and watch the tenant refuse to answer for a different person or a hint it did not sign for you.
Partly readyUses both lab tenants
The lesson
Builds on: Connecting a sign-in to an account.
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.
- G66 Second lab tenant for every learner: additional tenants need a paid subscription or a BTL grant, so labs that use Lab Mail cannot be completed by an ordinary learner yet
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.
Sign in to start this lab and check your progress. Log in or create an account.
Sign in as Ben although the hint named Ava
Recorded as
oauth.authorizesucceeded (user_signed_in) forlab-collageabout[email protected].Get a silent code with an expired ID token as the hint
Recorded as
oauth.authorizesucceeded (code_issued) forlab-collageabout[email protected].See the tenant refuse to answer for someone else
Recorded as
oauth.authorizerejected (id_token_hint_mismatch) forlab-collage.Send a hint the tenant did not sign for lab-collage
Recorded as
oauth.authorizerejected (invalid_id_token_hint) forlab-collage.
Setup
You need
ID_TOKEN_AVA, the ID token Ava received in Key accounts on issuer and subject. It expired long ago, which is the point. If your shell lost it, sign in as Ava once and keepID_TOKEN_AVA=$ID_TOKEN, then wait for it to expire.In your lab browser's private window, open
$ISSUER/accountand sign out.source ~/btl-oidc.sh, runbtl-lab callbackbefore each request, and press Start.
Walkthrough
Suggest an account.
signin login_hint=ava%40example.com
The tenant's sign-in form opens with [email protected] already filled in.
Why it matters: a hint saves the person effort. It skips nothing.
Clear the field and sign in as Ben instead. Redeem and validate:
subis Ben's. Your relying party expectedacct-8812, so it signs Ben in to his own account, if he has one, and shows him nothing of Ava's.
Why it matters: the evidence of who signed in is the validated iss and sub, never the hint you sent.
Open your browser history and find the authorization URL: the email address is there in clear. The tenant uses
login_hintas an email address to prefill its form, so that is the format its documentation calls for.
Why it matters: hints travel through the browser and can be recorded wherever URLs are. Send one only when it saves real effort, in the format the provider documents.
Hint with an earlier ID token. Sign out, sign in as Ava, then ask silently for her by her old token:
part "$ID_TOKEN_AVA" | jq '{sub, exp, expired: (.exp < now)}'
signin prompt=none "id_token_hint=$ID_TOKEN_AVA"
expired is true, and a code still comes back.
Why it matters: the hint points to a person. It is not proof of a current sign-in, so its exp does not matter, and it was addressed to your client, not to the provider.
Switch people under the hint. In another tab of the same window, sign out and sign in as Ben at
$ISSUER/login. Run the step 4 request again with a freshsignin: the listener printserror=login_required. Run it once more without the hint:
signin prompt=none
A valid code comes back, for Ben.
Why it matters: without id_token_hint, a silent request can return a perfectly valid sign-in for the wrong account. With it, the provider knows that is not the person you asked about.
Break it
A real hint meant for someone else. Sign in to
lab-mail-collageat Lab Mail as Ava Lin and keep that ID token, then send it to Lab Photos as a hint:
ISSUER_A=$ISSUER CLIENT_A=$CLIENT_ID SECRET_A=$CLIENT_SECRET
ISSUER=$ISSUER2 CLIENT_ID=$MAIL_CLIENT_ID CLIENT_SECRET=$MAIL_CLIENT_SECRET
signin
redeem '<code>'
MAIL_ID_TOKEN=$ID_TOKEN
ISSUER=$ISSUER_A CLIENT_ID=$CLIENT_A CLIENT_SECRET=$SECRET_A
signin prompt=none "id_token_hint=$MAIL_ID_TOKEN"
The listener prints error=invalid_request and a description saying the hint must be an ID token this issuer signed for this client. Lab Photos accepts only hints it signed for lab-collage, and only with a key it still publishes.
Write the relying-party check the lesson ends on. After a hint-driven sign-in, compare the result's
subwith the session's before applying anything:
EXPECTED_SUB=$(part "$ID_TOKEN_AVA" | jq -r .sub)
[ "$(part "$ID_TOKEN" | jq -r .sub)" = "$EXPECTED_SUB" ] && echo "same person: continue" || echo "different person: discard pending work, end session"
Feed it Ben's token from step 5: it refuses to apply anything to Ava's session.
Check your work
Press Check my progress. The checks look for Ben's sign-in despite Ava's hint, the silent code issued with an expired hint, the id_token_hint_mismatch refusal, and the refused Lab Mail hint.
Nothing about the hint changed what the tenant asked for at sign-in: Audit shows the same user_signed_in event for Ben that any password sign-in produces.
Cleanup
Sign Ben out and sign Ava back in. Nothing in either tenant was changed.
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.