# OAuth 2.0 Token Decoder

> Decode JWT-format OAuth 2.0 access tokens to check their scope, audience, client and expiry.

- Page: https://decoder.tools/oauth-token-decoder
- Category: Web, API & Tokens
- Status: live, runs in the browser
- Last reviewed: 2026-10-23

An OAuth token decoder reads an access token that is a JSON Web Token and shows its claims: which scopes it grants, which API it's for, which client asked for it and when it expires. Opaque access tokens are random strings and can't be decoded at all.

## Example

```text Input
eyJhbGciOiJIUzI1NiIsInR5cCI6ImF0K2p3dCJ9.eyJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20iLCJzdWIiOiJ1c2VyLTQyIiwiYXVkIjoiaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20iLCJjbGllbnRfaWQiOiJ3ZWItYXBwIiwic2NvcGUiOiJyZWFkOm9yZGVycyB3cml0ZTpvcmRlcnMiLCJpYXQiOjE3MDAwMDAwMDAsImV4cCI6MTcwMDAwMDkwMH0.A5X4AFDecdKhYEb55D1QwhPe_5ot0r7w9CQRxY-FgvU
```

```text Output
HEADER
{
  "alg": "HS256",
  "typ": "at+jwt"
}

PAYLOAD
{
  "iss": "https://auth.example.com",
  "sub": "user-42",
  "aud": "https://api.example.com",
  "client_id": "web-app",
  "scope": "read:orders write:orders",
  "iat": 1700000000,
  "exp": 1700000900
}
```

The `typ` of `at+jwt` marks a JWT access token as defined by RFC 9068.

## JWT versus opaque access tokens

OAuth 2.0 (RFC 6749) doesn't say what an access token looks like. Providers use one of two designs:

- **JWT access tokens** carry their claims inside, so an API can validate them locally with the provider's public key. Auth0, Okta, Microsoft Entra ID and Keycloak commonly issue these. You can decode them here.
- **Opaque tokens** are random reference strings. Only the authorization server knows what they mean, and an API checks them by calling the provider's introspection endpoint (RFC 7662). There is nothing inside to decode.

A token that starts with `eyJ` and has two dots is almost certainly a JWT.

## Access token claims (RFC 9068)

| Claim | Meaning |
|---|---|
| `iss` | Authorization server that issued the token |
| `sub` | The user, or the client itself for machine-to-machine tokens |
| `aud` | The API (resource server) the token is for |
| `client_id` | The application that requested the token |
| `scope` | Space-separated permissions, for example `read:orders write:orders` |
| `exp`, `iat` | Expiry and issue time, in Unix seconds |
| `jti` | Unique token ID |

## How to use the OAuth token decoder

1. Copy the token from the `Authorization: Bearer …` header or the token response. The `Bearer` prefix can stay.
2. Check `aud` and `scope`. A 403 from an API usually means a missing scope or the wrong audience.
3. Check `exp`. Access tokens are short-lived, often 5 to 60 minutes.

## Debugging common errors

- **401 Unauthorized** usually means the token is expired, malformed or signed by an issuer the API doesn't trust. Check `exp` and `iss`.
- **403 Forbidden** usually means the token is valid but lacks a scope, or `aud` names a different API.
- **"invalid audience"** means the client requested the token for the wrong resource. Set the `audience` or `resource` parameter in the token request.

## OAuth access tokens at a glance

| | |
|---|---|
| Specifications | RFC 6749 (OAuth 2.0), RFC 9068 (JWT access tokens), RFC 7662 (introspection) |
| Formats | JWT (decodable) or opaque (not decodable) |
| Sent as | `Authorization: Bearer <token>` |
| Typical lifetime | 5 to 60 minutes |

## FAQ

### Can I decode a refresh token?

Usually not. Refresh tokens are almost always opaque, because only the authorization server ever needs to read them.

### Why can't this tool decode my access token?

It's probably opaque. If it has no dots or doesn't start with `eyJ`, it's a reference token, and only the provider's introspection endpoint can tell you what it means.

### Is an access token the same as an ID token?

No. An access token is for calling an API. An ID token is an OpenID Connect token that tells the client who logged in. Use the [OIDC token decoder](/oidc-token-decoder) for those.
