Beyond the LoginBetaunderstand identity, one concept at a time

Exchanging a code for tokens

The printer has received a code and accepted the authorization response. Your browser's return journey is complete, but the printer still needs the credential it will present to the photo API.

Its backend now makes a direct HTTPS request to the photo service's token endpoint.

Building the token request

This example uses HTTP Basic client authentication with an entirely fictional client secret. The encoded header represents photo-printer:demo-only-not-a-real-secret. Base64 encoding is not encryption; HTTPS protects the request in transit.

POST /token HTTP/1.1
Host: auth.photos.example
Authorization: Basic cGhvdG8tcHJpbnRlcjpkZW1vLW9ubHktbm90LWEtcmVhbC1zZWNyZXQ=
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=demo-code-7
&redirect_uri=https%3A%2F%2Fprinter.example%2Foauth%2Fcallback
&code_verifier=btl_training_verifier_for_one_attempt_only_2026

The body is form-encoded, not JSON. Its line breaks are for display only.

grant_type identifies the kind of exchange. code supplies the intermediate credential. redirect_uri repeats the address used in the authorization request, and code_verifier supplies the PKCE proof.

Including a redirect URI here does not cause another browser redirect. It gives the token endpoint a value to check against the earlier exchange.

HTTP Basic is only the client authentication method selected for this example. Other registrations use methods such as signed assertions. A public client does not become confidential by inventing a shared secret; it identifies itself with its client ID when it does not authenticate. Clients and registration will explain these differences in detail.

Checking the exchange

The authorization server checks the client's authentication, the code's validity and client binding, the redirect URI, and the PKCE proof. It also enforces expiry and single use of the code. These checks belong at the token endpoint even if the earlier browser interaction appeared successful.

A successful response might be:

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache

{
  "access_token": "demo-access-token-7",
  "token_type": "Bearer",
  "expires_in": 600,
  "scope": "photos.read"
}

The ten-minute lifetime is a choice for this example, not a universal OAuth duration. A refresh token is optional and is not issued in this example. We will study requesting and using continued access in the refresh token lessons.

The client handles the returned token type, lifetime, and actual scope. A scope value is required when the granted scope differs from the request; when it is omitted, the client must interpret that omission according to the protocol rather than assume additional permissions.

Using the result

The printer can now make an API request:

GET /photos HTTP/1.1
Host: api.photos.example
Authorization: Bearer demo-access-token-7

The token endpoint's success does not force the API to accept every operation. The API must validate the token for its intended use and enforce permission and resource checks. Tokens and resource servers will cover those checks, token formats, and API failure responses.

For now, keep the credential roles distinct: the client credential authenticates the printer, the code represents the authorization exchange, the verifier supplies its per-attempt proof, and the access token accompanies the API request.

PUT IT INTO PRACTICE

Check your understanding

Try these questions before moving on. If an answer isn't right, use the feedback and try again.

0 of 2 answered correctly

Enable JavaScript to answer these questions and save progress in this browser.

QUESTION 1 OF 2Why does the token request repeat redirect_uri?

QUESTION 2 OF 2The token response contains an access token but no refresh token. Does that necessarily indicate a broken response?

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

Learn identity