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

Prove each client can use only the grant that fits

Classify every lab client by whose access it needs and where it runs, then confirm with real refusals that registration and Flow policy hold each one to its grant.

ReadyUses your lab tenant

The lesson

Builds on: Client credentials, 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. A user-facing client cannot act as itself

    Recorded as oauth.token rejected (unauthorized_client) for lab-printer.

  2. A public client cannot use client credentials

    Recorded as oauth.token rejected (client_authentication_required) for lab-printer-app.

  3. A refresh token cannot start access

    Recorded as oauth.token rejected (invalid_grant) for lab-printer.

  4. A token response is refused while the implicit grant is off

    Recorded as oauth.authorize rejected (unauthorized_client).

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 shell variables. This lab uses several clients, so each has its own name.

export ISSUER="https://tenant-<id>.beyondthelogin.dev"
export PRINTER_ID="<lab-printer client ID>"; read -rs PRINTER_SECRET
export ORDERS_ID="<lab-print-orders client ID>"
export APP_ID="<lab-printer-app client ID>"
enc() { jq -rn --arg v "$1" '$v|@uri'; }
  1. Press Start on this page.

Walkthrough

  1. Compare what the tenant advertises with its Flow policy.

GET$ISSUER/.well-known/openid-configuration Open in console
GET $ISSUER/.well-known/openid-configuration HTTP/1.1

grant_types_supported lists exactly the grants Flow policy allows: authorization_code, refresh_token and client_credentials after the earlier labs. response_types_supported lists code.

  1. Classify the clients you have built, from OAuth > Clients, using the lesson's questions.

ClientWhose accessWhere it runsGrant
lab-printerAva'sbackend, confidentialauthorization code with PKCE, plus refresh
lab-printer-appAva'sinstalled app, publicauthorization code with PKCE on a loopback address
lab-print-ordersits ownbackend, confidentialclient credentials
lab-photo-apinone: it checks tokensbackend, confidentialno grant, introspection only
Token Decoderthe signed-in user'sbrowser, publicauthorization code with PKCE

Why it matters: whose access it is separates the grants first. Where the client runs then decides how it uses its grant, not which grant it gets.

  1. A service client cannot start a user flow. Open an authorization request for lab-print-orders.

echo "$ISSUER/oauth/authorize?response_type=code&client_id=$ORDERS_ID&redirect_uri=$(enc http://127.0.0.1:8765/callback)&scope=prints.create&state=x"

It stops on the tenant's error page: the client has no redirect URIs, so there is nowhere to return a person to.

  1. A user-facing client cannot act as itself.

curl -s -u "$PRINTER_ID:$PRINTER_SECRET" -d grant_type=client_credentials "$ISSUER/oauth/token" | jq

The answer is unauthorized_client, "The tenant flow policy or this client's settings do not allow this grant type." Flow policy allows the grant, but the printer's registration does not.

  1. A public client cannot use client credentials at all: curl -s -d grant_type=client_credentials -d "client_id=$APP_ID" "$ISSUER/oauth/token" | jq answers unauthorized_client, "Public clients cannot authenticate, so they cannot use this grant or endpoint."

  1. A refresh token does not start access. Present one that was never issued.

curl -s -u "$PRINTER_ID:$PRINTER_SECRET" -d grant_type=refresh_token -d refresh_token=never-issued "$ISSUER/oauth/token" | jq

The answer is invalid_grant. Refresh extends an authorization the client already holds; it is never the first step.

  1. Flows to avoid.

    • The password grant: curl -s -d grant_type=password -d [email protected] -d password=demo-password-not-real -d "client_id=$APP_ID" "$ISSUER/oauth/token" | jq answers unsupported_grant_type. The placeholder is not Ava's real password; never send a real one.

    • The implicit grant: in $ISSUER/token-decoder, choose response type token and start. The decoder reports unauthorized_client, because Flow policy does not allow the implicit grant.

Why it matters: each grant follows from the situation, and registration plus Flow policy make the wrong choice fail instead of quietly working.

Break it

Steps 3 to 7 are the deliberate refusals. No setting changes in this lab.

Check your work

Press Check my progress. Logs also has oauth.authorize rejected invalid_redirect_uri for step 3 and oauth.token rejected unsupported_grant_type for the password grant. Both are refused before a client is identified, so they appear only in Logs.

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