OPENID CONNECT · LAB
Sign out of one app and watch the tenant sign you back in
Reproduce the library computer problem with two clients in one tenant, see that local logout leaves the provider session running, then end the provider session yourself and see what survives.
ReadyUses your lab tenant
The lesson
Builds on: Offline access and refresh behavior.
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.
- G17 OIDC logout: RP-initiated, front-channel, back-channel, session management
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.
Create the second app
Recorded as
tenant.oauth.clients.createsucceeded.Sign in to the second app with no password
Recorded as
oauth.authorizesucceeded (code_issued) forlab-tmp-slideshowabout[email protected].Get signed back in to lab-collage after local logout
Recorded as
oauth.authorizesucceeded (code_issued) forlab-collageabout[email protected].Sign out at the tenant itself
Recorded as
account.sign_outsucceeded (signed_out) about[email protected].See prompt=none fail once the provider session ended
Recorded as
oauth.authorizerejected (login_required) forlab-collage.Refresh the calendar connection after sign-out
Recorded as
oauth.tokensucceeded forlab-collage.
Setup
Single sign-on across two of your clients, local logout and the tenant's own sign-out are all real. ID tokens carry no sid and the tenant has no logout protocol yet (G17), which this lab shows rather than hides.
Press Start. In Lab Photos, open OAuth > Clients and create
lab-tmp-slideshow, a photo slideshow app: public, PKCE required, grantauthorization_code, scopesopenid profile, consent mode Remember, redirect URIhttp://127.0.0.1:8765/callback. Store its client ID:
source ~/btl-oidc.sh
SLIDES_ID="<lab-tmp-slideshow client ID>"
COLLAGE_ID=$CLIENT_ID COLLAGE_SECRET=$CLIENT_SECRET
Run
btl-lab callbackbefore each request.
Walkthrough
The connection that should outlive any sign-out. In a private window, sign in to
lab-collageas Ava with offline access and keep its refresh token:
SCOPE="openid photos.read offline_access"
signin prompt=consent
redeem '<code>'
REFRESH_COLLAGE=$REFRESH; COLLAGE_ID_TOKEN=$ID_TOKEN
Why it matters: this is the yearly calendar connection, an authorization Ava granted, not a sign-in.
Sign in to the second app in the same window.
CLIENT_ID=$SLIDES_ID CLIENT_SECRET="" SCOPE="openid profile"
signin
redeem '<code>'
No password page: a consent page the first time, then a code. The public client redeems with its client ID only.
Why it matters: one tenant session signs the browser in to every client of that tenant.
Local logout of the collage app. Delete your local session record and the tokens the session held, then start a new collage sign-in:
unset COLLAGE_ID_TOKEN TOKEN ID_TOKEN
CLIENT_ID=$COLLAGE_ID CLIENT_SECRET=$COLLAGE_SECRET SCOPE="openid profile email"
signin
It completes with no password.
Why it matters: ending the session you control leaves the provider's session running, so the next person at this browser becomes Ava. Nothing was forged.
Look for a way to name the provider's session.
part "$ID_TOKEN" | jq '{sid}'
curl -s "$ISSUER/.well-known/openid-configuration" | jq '{end_session_endpoint, frontchannel_logout_supported, backchannel_logout_supported, logout: .btl_endpoint_status["/oidc/logout"]}'
sid is null, there is no end_session_endpoint, and the logout endpoint's status is not_implemented.
Why it matters: without a provider session identifier there is nothing to name in a logout message.
End the provider session yourself. Open
$ISSUER/accountin the private window and choose Sign out. Nowsignin prompt=nonereturnserror=login_requiredforlab-collage, and the same forlab-tmp-slideshow.
Why it matters: only the provider can end the provider's session.
See what survived. Refresh the calendar connection:
curl -s -u "$COLLAGE_ID:$COLLAGE_SECRET" "$ISSUER/oauth/token" -d grant_type=refresh_token --data-urlencode "refresh_token=$REFRESH_COLLAGE" | jq '{scope, refresh_token: (.refresh_token != null)}'
It succeeds. Keep the new refresh token in REFRESH_COLLAGE. The slideshow's local session would also still be inside its own deadlines, because nothing told it.
Why it matters: a sign-out should not cancel December's calendar, and other apps keep their sessions until their own timeouts or a logout message.
Decide what Sign out means in your app and write it down: Sign out ends the local session only, and Sign out here and at Lab Photos ends the local session, then sends the browser to
$ISSUER/accountwhere the person can sign out themselves, until RP-initiated logout exists.
Why it matters: what logout means is a product choice, made openly, not a side effect.
Break it
Treat sign-out as revocation. Write the calendar job so that it stops when the person signs out of the tenant. Step 6 shows the assumption is wrong: the tenant does not revoke the grant at sign-out. Disconnecting the calendar is a separate action, which your app offers on its own:
curl -s -u "$COLLAGE_ID:$COLLAGE_SECRET" "$ISSUER/oauth/revoke" --data-urlencode "token=$REFRESH_COLLAGE" -o /dev/null -w '%{http_code}\n'
Check your work
Press Check my progress. The checks look for the second client, a code for it with no new sign-in, a code for lab-collage after its local logout, Ava's sign-out at the tenant, a login_required answer afterward, and a successful refresh after the sign-out.
In Audit, the two codes after the first sign-in have no user_signed_in before them. That is single sign-on, seen from the provider.
Cleanup
Revoke
REFRESH_COLLAGEif Break it did not.Delete
lab-tmp-slideshow.Set
SCOPE="openid profile email".