# OpenID Connect (OIDC) Token Decoder

> Decode an OpenID Connect id_token and read its identity claims: issuer, subject, audience, nonce and expiry.

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

An OIDC token decoder reads the ID token an OpenID Connect provider returns after login. An ID token is a JWT, so decoding it shows the header and the identity claims: who the user is, who issued the token, which app it is for and when it expires.

## Example

```text Input
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmV4YW1wbGUuY29tIiwic3ViIjoiMjQ4Mjg5NzYxMDAxIiwiYXVkIjoibXktY2xpZW50LWlkIiwibm9uY2UiOiJuLTBTNl9XekEyTWoiLCJlbWFpbCI6ImFkYUBleGFtcGxlLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJpYXQiOjE3MDAwMDAwMDAsImV4cCI6MTcwMDAwMzYwMH0.FQ9oNgmkz3hZBfzNfBbxwj3nk6GVVVTyvDRj_4tgntM
```

```text Output
HEADER
{
  "alg": "HS256",
  "typ": "JWT"
}

PAYLOAD
{
  "iss": "https://accounts.example.com",
  "sub": "248289761001",
  "aud": "my-client-id",
  "nonce": "n-0S6_WzA2Mj",
  "email": "ada@example.com",
  "email_verified": true,
  "iat": 1700000000,
  "exp": 1700003600
}
```

Real providers sign ID tokens with RS256 or ES256. This sample uses HS256 to keep it short.

## ID tokens versus access tokens

OpenID Connect adds a login layer on top of OAuth 2.0. When a user signs in, the client gets up to three tokens:

- The **ID token** tells the *client app* who logged in. It is always a JWT.
- The **access token** is sent to an *API* to authorize requests. It may or may not be a JWT. See the [OAuth token decoder](/oauth-token-decoder).
- The **refresh token** gets new tokens later. It is usually opaque.

A common mistake is sending the ID token to an API as if it were an access token. APIs should only accept access tokens issued for their own audience.

## ID token claims

| Claim | Meaning |
|---|---|
| `iss` | The provider's issuer URL. Must match the provider you configured exactly |
| `sub` | Stable, unique user ID at that provider. Use this, not the email, as the user key |
| `aud` | Your client ID. Reject the token if it isn't yours |
| `nonce` | Echoes the value your app sent in the login request, to stop replay |
| `exp`, `iat` | Expiry and issue time, in Unix seconds |
| `auth_time` | When the user actually authenticated |
| `email`, `email_verified`, `name` | Profile claims, present when the matching scopes were requested |

## How to use the OIDC token decoder

1. Paste the `id_token` from the token response, a browser redirect or your app's debug output.
2. Compare `iss` and `aud` with your provider and client configuration.
3. Check `exp` and `nonce`. Then confirm your app validates the signature with the provider's keys (its `jwks_uri`).

## What a client must validate

Per OpenID Connect Core §3.1.3.7, before trusting an ID token a client should check:

1. The signature, using a key from the provider's JWKS endpoint.
2. `iss` equals the expected issuer.
3. `aud` contains the client's own ID.
4. `exp` is in the future.
5. `nonce` equals the value sent in the authentication request.

## OIDC ID tokens at a glance

| | |
|---|---|
| Specification | OpenID Connect Core 1.0 |
| Format | Always a signed JWT |
| Meant for | The client application, not APIs |
| Usual algorithms | RS256, ES256 |
| Key discovery | `/.well-known/openid-configuration` → `jwks_uri` |

## FAQ

### Should I identify users by email or by sub?

By `sub`, combined with `iss`. Email addresses can change and can be reused. `sub` is guaranteed stable and unique for that provider.

### Why is the aud claim an array?

The spec allows `aud` to be a string or an array of strings. If it's an array, your client ID must be one of the entries. Some specs also require an `azp` (authorized party) claim in that case.

### Can I decode a Google or Microsoft ID token here?

Yes. They are standard JWTs. The decoder shows the claims locally in your browser. It doesn't contact the provider or verify the signature.
