ID Token vs Access Token: What are the Key Differences?
ID tokens prove who logged in. Access tokens prove what they can do. Learn the differences, the security mistakes, and how to validate each.
ID tokens prove who logged in. Access tokens prove what they can do. Learn the differences, the security mistakes, and how to validate each.
OAuth 2.0 and OpenID Connect issue different tokens for different purposes, and confusing the two is how security holes get shipped. The ID token proves who logged in. The access token proves what they are allowed to do. Treat them as interchangeable and you either leak identity data to an API that should never see it, or you let an API make authorization decisions on claims that say nothing about permissions.
This guide breaks down both token types: what they contain, who consumes them, how to validate them, and the specific mistakes that turn a token mix-up into a vulnerability. If you want the protocol-level decision behind all of this first, our guide on when to use OAuth 2.0 and OpenID Connect covers which flow issues which token. The same token discipline now applies to identity for agentic AI, where machine actors request access tokens at a volume no human ever could.
An ID token is a signed JSON Web Token (JWT) that an authorization server issues after a user successfully logs in. It answers exactly one question: who is this user? OpenID Connect introduced the ID token as the standard way for an application to receive verified identity information.
The ID token is meant for your client application: your frontend, mobile app, or single-page app. It carries claims about the user such as name, email, and a unique identifier. Your client decodes the token to confirm authentication succeeded and to personalize the experience. The flows that mint it are the same ones described in our overview of login, password, passkey, WebAuthn, TOTP, and SSO.
A typical ID token payload includes the issuer, subject, audience, and a set of identity claims:
{
"iss": "https://auth.example.com",
"sub": "user-12345",
"aud": "my-client-app",
"name": "Jane Developer",
"email": "[email protected]",
"iat": 1718000000,
"exp": 1718003600
}
The sub claim uniquely identifies the user. The iss and aud claims tell you which authorization server issued the token and which application it was issued for. Together, they let your client confirm the token came from a trusted source and was intended for your app.
An access token is a credential that grants permission to call protected APIs. Where the ID token answers "who is this user?", the access token answers what can this user do? It carries authorization information, not identity information.
Resource servers, meaning your backend APIs, consume access tokens. When a client calls an API it sends the access token in the Authorization: Bearer <token> header. The API validates the token and checks whether the granted permissions allow the requested action. A gateway like Ory Oathkeeper can perform that validation at the edge before a request ever reaches your service.
An important distinction: access tokens are not always JWTs. OAuth 2.0 does not mandate a format, so an access token can be an opaque string that only the authorization server can interpret. Even when an access token happens to be a JWT, your client should treat it as opaque and never decode it for user information.
Access tokens typically contain:
read:messages or write:data that define allowed actions.The core distinction comes down to purpose and audience. ID tokens handle authentication for the client. Access tokens handle authorization for the API. Mixing them up is what creates vulnerabilities.
| Feature | ID Token | Access Token |
|---|---|---|
| Primary purpose | Authentication: proves the user logged in | Authorization: grants permission to access APIs |
| Intended recipient | Client application | Resource server / API |
| Typical contents | Identity claims (name, email, profile) | Scopes and permissions |
| Format | Always a JWT | JWT or opaque string |
| Who validates it | OAuth client | Resource server |
The ID token stays with your client application. It confirms authentication happened and provides user details for display or session management. Your client reads it, validates it, and uses the claims inside. The access token travels to APIs. It proves the bearer has permission to perform specific actions on protected resources. Your client passes it along but does not inspect its contents.
ID tokens are always JWTs per the OpenID Connect specification, so you can rely on the format and decode them in your client. Access tokens may be JWTs or opaque strings; OAuth 2.0 leaves the choice to the implementation. This matters because an authorization server might switch from opaque tokens to JWTs without warning, and client code that assumed a structure will break. Treat the format as the server's business, not yours.
ID tokens contain identity claims such as sub, name, email, picture, and other user attributes that describe who the user is. Access tokens contain authorization data: scopes, permissions, and resource identifiers that describe what the bearer can do. Access tokens typically avoid sensitive personally identifiable information because they travel to external APIs where that data has no business being.
Both tokens originate from the same authorization server, but they flow to different destinations. The ID token is sent to your client and remains there: your frontend or mobile app decodes it, extracts user information, and may store it for the session. The access token passes through your client to reach the resource server. Your client attaches it to API requests but does not read it.
Using an ID token to call an API is a common mistake and a real security risk. ID tokens lack the permission scopes APIs rely on to make authorization decisions.
Consider the scenario. Your API receives a valid ID token for a user named Jane. The token proves Jane logged in. It says nothing about whether Jane can read financial reports, delete accounts, or hit admin endpoints. Without scopes, the API has no basis for an authorization decision. That gap is exactly why a dedicated policy layer like Ory Keto exists: to decide what an authenticated principal can actually touch.
The inverse mistake is using access tokens to identify users. Access tokens may be opaque strings with no readable content, or JWTs whose claims are meant only for the resource server.
/userinfo endpoint with the access token to retrieve user claims.Your client application has no business inspecting access tokens. Treat them as opaque credentials you pass to APIs, and let the resource server do the reading.
Issue standards-based ID and access tokens with Ory Hydra
Use the ID token. Decode it to display the user's name, load their avatar, or adjust the UI based on identity claims. This is exactly what ID tokens are designed for. After a successful login, your client receives the ID token and can extract user information immediately without an extra API round trip.
Use the access token. Attach it to the Authorization: Bearer header. The API validates the signature, checks expiration, and confirms the scopes allow the requested operation. Your client does not inspect the access token; it passes the token along and lets the API handle validation. For the mechanics of running that validation server, see how to run an open-source OAuth2 server for API security.
Both tokens are relevant. The ID token provides client-side user context for personalization; the access token authorizes API calls. Store both securely. For SPAs, in-memory storage avoids XSS exposure. For mobile apps, use platform-specific secure storage, such as Keychain on iOS or Keystore on Android. The browser-specific tradeoffs are covered in our guide to OAuth2 for mobile apps, SPAs, and browsers.
Typically, only access tokens apply. The OAuth 2.0 client credentials flow issues access tokens for service-to-service communication. Because no user authenticates, no ID token is issued. A backend service presents its own credentials (client ID and secret) and receives an access token scoped to its permitted actions.
Refresh tokens complete the OAuth 2.0 token lifecycle. They are long-lived credentials that allow users to obtain new access tokens without re-authenticating. Access tokens are intentionally short-lived, often 15 minutes to an hour, to limit the damage if one is compromised.
When an access token expires, your client uses the refresh token to request a new one from the authorization server, and the user does not see a login prompt. ID tokens are not usually refreshed directly. But when your client exchanges a refresh token for a new access token, the authorization server may issue a fresh ID token alongside it, keeping identity claims current without re-authentication.
Proper validation prevents token forgery and replay attacks. Both token types require similar steps, but different parties perform them.
Retrieve the authorization server's public keys from its JWKS (JSON Web Key Set) endpoint and use them to verify the JWT signature. This confirms the token was issued by a trusted authority and has not been tampered with.
Check that iss matches your expected authorization server URL. For ID tokens, verify aud matches your client ID. For access tokens, verify aud matches your API identifier. A token with an unexpected issuer or audience signals either misconfiguration or an attack. Ory's Hydra audiences guide walks through the process of binding tokens to specific resource servers.
Validate that exp (expiration) is in the future and iat (issued at) is in the past. If present, check nbf (not before) to ensure the token sits within its valid window. Expired tokens are invalid tokens; accepting them defeats the purpose of short lifetimes.
For access tokens, verify that the scope claim includes the permissions required for the requested operation. A token with read:messages cannot authorize a write. For ID tokens, confirm the expected identity claims are present. If your app requires an email, verify the email claim exists and is not empty.
AI agents and automated systems need the same token-based authorization as human users, often at far higher volume. The principles do not change: access tokens govern what an agent can do through scopes and fine-grained permissions. This is where the identity for agentic AI model matters most, because an over-permissioned agent generates new intent on its own and can weaponize a broad token at machine speed.
Machine-to-machine flows use the OAuth 2.0 client credentials grant, which issues only access tokens. Since no human authenticates, no ID token is generated. Each agent receives an access token scoped to its specific permitted actions, following least-privilege principles. The threat model for these flows is covered in agentic AI security, and the OAuth-plus-MCP specifics in agentic AI security with MCP and OAuth.
Organizations deploying agents at scale benefit from treating each agent as a first-class identity with proper token-based access control. That gives you auditability, permission boundaries, and instant revocation when an agent misbehaves or is compromised. For an implementation walkthrough, the MCP server authentication with Ory Hydra guide shows how tokens secure agent tool calls end-to-end.
Ory Hydra is an OAuth 2.0 and OpenID Connect provider that issues properly structured ID tokens and access tokens. It supports flexible deployment options: open-source, enterprise-licensed, or fully managed Ory Network, so teams can run identity infrastructure in the environment that best fits their requirements.
Built on open standards, Ory works for both human and machine identities. Pair Hydra with Ory Keto for the fine-grained authorization decisions tokens alone cannot make, and route agent and user traffic through the broader customer identity and access management stack. For teams building applications that require standards-compliant token flows, Ory provides the foundation without vendor lock-in.
Explore Ory's identity solution for AI agents
A JWT is a format, not a token type. ID tokens are always JWTs per the OpenID Connect specification. Access tokens can be JWTs or opaque strings, depending on how the authorization server is configured.
No. Using an ID token to call APIs is a security anti-pattern. ID tokens lack authorization scopes and are intended only for the client application. APIs that accept ID tokens cannot enforce permission boundaries.
A bearer token is any token that grants access to whoever holds it; the term describes how a token is used, not what it contains. Access tokens are typically bearer tokens sent in the Authorization: Bearer header. ID tokens are not bearer tokens. They are consumed directly by the client and never sent to APIs.
Short access token lifetimes limit the blast radius if one leaks. Refresh tokens live longer so users are not forced to re-authenticate constantly, but they are stored more carefully and can be revoked, which contains the risk a long-lived credential would otherwise carry.
See how Ory Hydra and Keto pair for token-based authorization
The rule is simple enough to tattoo on a code review checklist: ID tokens are for your client; access tokens are for your APIs; and neither does the other's job. Decode ID tokens, treat access tokens as opaque, validate both against issuer, audience, and expiry, and check scopes before you authorize anything. The teams that internalize this early never ship the "any logged-in user can hit any endpoint" bug. The ones who tend not to learn it from an incident report. For where token discipline fits the wider picture, the customer identity and access management hub maps identity and authorization across human and machine actors alike.