OAUTH 2.0 · LAB
Compare a signed OAuth 1.0 request with a real bearer request
Recompute the lesson's OAuth 1.0 signature and see how fragile it was, then show with your tenant how each row of the lesson's comparison table looks in OAuth 2.0.
ReadyIncludes a simulationUses your lab tenant
The lesson
Builds on: The refresh token grant.
New to the labs? Start with the lab toolkit and the shared cast and names every lab uses.
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.
The printer obtains a bearer token
Recorded as
oauth.tokensucceeded forlab-printerabout[email protected].The token works for whoever presents it
Recorded as
oidc.userinfosucceeded (userinfo_served) forlab-printer.A separate resource server checks the token
Recorded as
oauth.introspectsucceeded (other_client_token_found) forlab-photo-api.The bearer token is withdrawn at the server
Recorded as
oauth.revokesucceeded (access_token_found) forlab-printer.
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
Set the
lab-printervariables,APP_ID, andAPI_IDandAPI_SECRETforlab-photo-api. Definestart_attempt,handle_callbackandredeemas in the Correlating requests and responses lab.Press Start on this page.
Walkthrough
Take apart the lesson's signed OAuth 1.0 request.
Simulation. no OAuth 1.0 service provider exists to call. OAuth 1.0 is obsolete and RFC 6749 replaced it, so steps 1 and 2 work only with the lesson's fictional values.
In the lesson's Authorization: OAuth ... header, mark which values identify (oauth_consumer_key, oauth_token), which prevent replay (oauth_timestamp, oauth_nonce) and which proves possession (oauth_signature). Neither the consumer secret nor the token secret appears.
Recompute the lesson's signature from its base string and its two fictional secrets.
BASE='GET&https%3A%2F%2Fapi.photos.example%2Falbums%2F42%2Fphotos&oauth_consumer_key%3Dphoto-printer%26oauth_nonce%3Ddemo-nonce-1%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1262304000%26oauth_token%3Ddemo-oauth1-token'
KEY='demo-oauth1-consumer-secret&demo-oauth1-token-secret'
printf '%s' "$BASE" | openssl dgst -sha1 -hmac "$KEY" -binary | openssl base64 -A; echo
It prints SOl5b3VkmEefUaZ+AdQOupVdNfA=, the lesson's oauth_signature before percent-encoding. Now make one change a real consumer might make by accident: write the URL with its default port, https%3A%2F%2Fapi.photos.example%3A443%2Falbums..., and run it again. The signature is completely different.
Why it matters: consumer and provider had to build the same base string byte for byte. A difference in port, space encoding or parameter order produced only "invalid signature", with no hint about which byte differed.
Real: a bearer token. Run
start_attempt, change the scope toopenid%20photos.read, approve as Ava,handle_callback, and exchange. Keep the access token asTOKEN. Call UserInfo with it, then paste the same token into a second terminal and call again.
GET$ISSUER/oidc/userinfo
Open in console
GET $ISSUER/oidc/userinfo HTTP/1.1
Authorization: Bearer $TOKENBoth calls answer 200.
Why it matters: an OAuth 2.0 bearer token works for whoever holds it, protected in transit by TLS rather than by a signature on each request. That is far easier to implement and is why so many later protections aim to keep tokens from leaking.
Real: one party issues, another accepts. Your tenant issued the token;
btl-lab introspect "$TOKEN"checks it aslab-photo-api, a separate resource server. In OAuth 1.0, one service provider did both.
Real: a framework of grants.
curl -s "$ISSUER/.well-known/openid-configuration" | jq .grant_types_supportedlists the grants your Flow policy allows. OAuth 1.0 had a single redirect-based flow.
Real: continued access.
btl-lab decode "$TOKEN"shows anexp. Continued access comes from the refresh token grant you used in the refresh token lab, not from a token with no defined lifetime.
Real: clients that cannot keep a secret.
lab-printer-appis a registered public client that uses PKCE instead of a secret. OAuth 1.0 had no defined approach.
Revision A's lesson, in OAuth 2.0. Run
start_attemptin your terminal and open the address in a different browser profile, as happens when someone shares a link, and approve as Ben there. The code arrives in that profile's address bar, the browser that approved. If it is carried back into your terminal's session from anywhere else,handle_callbackstops it onstate.
Why it matters: like oauth_verifier, the authorization code reaches the client only through the approving browser. state and PKCE handle the opposite case, a response pushed into the wrong session.
Break it
Revoke the token from step 3 with the printer's credentials:
curl -s -u "$CLIENT_ID:$CLIENT_SECRET" -d "token=$TOKEN" "$ISSUER/oauth/revoke".Repeat the UserInfo call in both terminals: both answer
401 invalid_token.
A bearer token is withdrawn at the server. No signing secret needs to change.
Check your work
Press Check my progress. Audit shows two oidc.userinfo userinfo_served events for the same client and subject, one from each terminal: the server cannot tell who presented the token.
Cleanup
None.