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

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.

  1. The printer obtains a bearer token

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

  2. The token works for whoever presents it

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

  3. A separate resource server checks the token

    Recorded as oauth.introspect succeeded (other_client_token_found) for lab-photo-api.

  4. The bearer token is withdrawn at the server

    Recorded as oauth.revoke succeeded (access_token_found) for lab-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

  1. Set the lab-printer variables, APP_ID, and API_ID and API_SECRET for lab-photo-api. Define start_attempt, handle_callback and redeem as in the Correlating requests and responses lab.

  2. Press Start on this page.

Walkthrough

  1. 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.

  1. 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.

  1. Real: a bearer token. Run start_attempt, change the scope to openid%20photos.read, approve as Ava, handle_callback, and exchange. Keep the access token as TOKEN. 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 $TOKEN

Both 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.

  1. Real: one party issues, another accepts. Your tenant issued the token; btl-lab introspect "$TOKEN" checks it as lab-photo-api, a separate resource server. In OAuth 1.0, one service provider did both.

  1. Real: a framework of grants. curl -s "$ISSUER/.well-known/openid-configuration" | jq .grant_types_supported lists the grants your Flow policy allows. OAuth 1.0 had a single redirect-based flow.

  1. Real: continued access. btl-lab decode "$TOKEN" shows an exp. Continued access comes from the refresh token grant you used in the refresh token lab, not from a token with no defined lifetime.

  1. Real: clients that cannot keep a secret. lab-printer-app is a registered public client that uses PKCE instead of a secret. OAuth 1.0 had no defined approach.

  1. Revision A's lesson, in OAuth 2.0. Run start_attempt in 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_callback stops it on state.

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

  1. Revoke the token from step 3 with the printer's credentials: curl -s -u "$CLIENT_ID:$CLIENT_SECRET" -d "token=$TOKEN" "$ISSUER/oauth/revoke".

  2. 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.

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