IntegrAuth Academy
Identity, security and practical AI — free, from zero. Byte-sized lessons, real diagrams, hands-on labs, zero fluff. Two programs, each with its own exam and certificate.
English is hard? Your browser can translate this page into Tamil, Telugu, Kannada, Malayalam or Hindi. Tech words stay in English so you learn the real names.
How?
- Chrome on phone: ⋮ menu → Translate
- Chrome on computer: right-click → Translate to …
- Edge: the translate icon in the address bar
ID tokens vs access tokens
Maya signs in to her pilates app. The app gets three tokens. Two look almost the same, because both can be a JWT. Your goal: say which token is for the app and which is for the API.
- The ID token is for the app. It says who signed in.
- The access token is for the API. It says what the caller may do.
- The API must check that
audnames the API itself. - Never send an ID token to an API.
Same look, different jobs
The sign-in from the last lesson gives the app an ID token, an access token and a refresh token. The ID token comes from OpenID Connect, the login layer on top of OAuth. Each token has one reader.
🪪 ID token — for the app
It answers: "Who just signed in, and how?" The app reads it. It holds Maya's user ID, the time she signed in and the nonce. The app uses it to start her session. It opens nothing.
🔑 Access token — for the API
It answers: "What may this caller do?" The app carries it to the API. The API reads it. The app should not depend on what is inside. It may be a JWT today and an opaque string tomorrow.
The API is also the resource server. It decides. The app is the client. It asks.
A hotel. At check-in you get a receipt with your name. That is the ID token. You also get a keycard. That is the access token. The receipt does not open the door.
The audience
Every JWT can carry an audience. It is the aud claim. It names the one party that may use the token.
| Token | aud holds | Who reads it |
|---|---|---|
| ID token | The app's client ID, such as pilates-app | The app |
| Access token | The API's name, such as pilates-api | The API |
Why the API must check the audience
Say the API accepted any token with a good signature. An ID token has one too. It travels widely. Anyone holding it could then call the API as Maya. This is token confusion. The token is real, but it is used for the wrong job.
The fix is simple. The API checks that aud names itself and rejects every other token. This also stops an access token made for another service, such as billing-api. See validating a JWT.
A quiz site uses the same identity provider. After Maya tries it, the site holds her ID token. A weak API that checks only signature and issuer would accept it. A strict API sees aud: quiz-site and answers 401.
The typ label: a second lock
The token header can carry a label. A JWT access token has typ: at+jwt. It means "access token in JWT form". An API can refuse any other token. Then it refuses an ID token even if the audience was set up wrong. Some providers do not add this label yet. Then the API relies on aud, the issuer and the scope.
Three more rules
- To learn who signed in, the app reads the ID token, not the access token.
- The refresh token goes only to the identity provider's token endpoint. See rotation.
- An opaque access token needs a lookup. The API asks the issuer, through introspection. The app does not. See opaque tokens.
Never send an ID token to an API as a bearer token. A bearer token works for whoever holds it. Need a token for another service? Ask for a new one with token exchange.
Go deeper: what the specs say
OpenID Connect Core says the app must check that the ID token's aud contains its own client ID. It also checks iss, exp and, if it sent one, the nonce. This mirrors the API-side check. The OIDC login lesson shows the whole flow.
RFC 9068 gives JWT access tokens the typ: at+jwt label. An API that follows it must check the label and reject any other. It also requires aud to name the API, and the API must reject any token that does not. Its security notes say the label helps the API tell access tokens from ID tokens. As of October 2026 this is the standard way to label JWT access tokens.
RFC 9068 lists these claims: iss, exp, aud, sub, client_id, iat and jti.
Some providers let the app ask for a chosen audience with a resource indicator in the request. The token then carries that API's name in aud. Basic words about the JWT are in What is a JWT?. The whole token family is in the tokens lesson.
🧪 Interactive lab — enable JavaScript to play with this one.
Paste an ID token into ID Token Check. Look at aud and the header. Is it a token an API should ever accept?