How to Decode a Bearer Token (and Read aud, exp, scope) Without Leaking It
Slug: decode-bearer-token-claims
Date: 2026-11-02
Category: Guide
Target CTA: https://toolbookly.com/jwtly
You copied an Authorization: Bearer eyJhbGciOi… header out of DevTools, Postman, or a log line, and you want to know what is inside: who the token is for (aud), who issued it (iss), which user (sub), what it allows (scope), and when it expires (exp). Searching “decode bearer token” or “hs256 decode” leads to plenty of paste boxes. This guide explains what a bearer token actually is, how to read its claims, and why you should do that on your own device.
Is a bearer token a JWT?
“Bearer” is an HTTP authentication scheme, not a token format. It means whoever holds this string gets access — no extra proof needed. The string after Bearer can be:
- A JWT (most common with OAuth 2.0 / OpenID Connect providers, Auth0, Cognito, Firebase, Supabase, Keycloak, Azure AD). It looks like three base64url segments joined by dots:
xxxxx.yyyyy.zzzzz, usually starting witheyJ. - An opaque token — a random string with no dots (for example many GitHub, Stripe, or Slack tokens). These cannot be decoded; only the issuer can look them up.
Quick test: if the value has exactly two dots and starts with eyJ, it is almost certainly a JWT and you can read it.
What is inside: header, payload, signature
A JWT is header.payload.signature:
- Header — JSON with
alg(for exampleHS256,RS256,ES256) and oftentypandkid - Payload — JSON with the claims
- Signature — proves the first two parts were not altered; it does not hide them
The header and payload are only base64url-encoded, not encrypted. Anyone holding the token can read them. That is why “decode” needs no key — and why the token itself is the secret you must protect.
The claims you usually care about
| Claim | Meaning | What to check |
|---|---|---|
iss |
Issuer | Is it the identity provider you expect? |
sub |
Subject (user or client ID) | Is this the account you think it is? |
aud |
Audience | Does it match your API? A wrong aud is a classic cause of 401s |
exp |
Expiry (Unix seconds) | Already in the past? Clock skew between machines? |
iat / nbf |
Issued-at / not-before | A future nbf makes a fresh token look “invalid” |
scope / scp / roles |
Permissions | Is the scope your endpoint requires actually present? |
azp / client_id |
Authorized party | Which app requested the token? |
Most “my token is rejected” bugs come down to aud, exp/nbf, or a missing scope. Reading the payload answers that in seconds.
Decoding is not verifying (HS256 vs RS256)
Decoding lets you read claims. Verifying checks the signature:
- HS256 / HS384 / HS512 use a shared secret. You need that secret to verify — and you should never paste a production secret into a website you do not control.
- RS256 / ES256 (and friends) use a public key, usually published at the issuer’s JWKS endpoint. Verifying with a PEM public key is safe to do locally.
Never trust claims from a token you have not verified in your actual server code. Decoding is for debugging, not for authorization.
Why pasting a bearer token online is risky
A bearer token is the credential. Until exp, anyone who sees it can call the API as that user. When you paste it into a decoder that sends the text to a server, it can end up in request logs, analytics, error trackers, or a “recent tokens” history. Some tools also put the token in the page URL, so it leaks into browser history and shared links. Access tokens are often valid for an hour or more, and refresh tokens far longer.
Checklist before decoding anywhere:
- Prefer a tool that decodes in your browser and keeps working offline
- Make sure the token never goes into the URL (query or hash)
- Never paste HS* production secrets into a third-party site
- If a live token was pasted somewhere you do not trust, revoke it or rotate the session
Decode a bearer token locally with Jwtly
Jwtly is ToolBookly’s JWT decoder. Paste the whole header value — Bearer eyJ… or even Authorization: Bearer eyJ… — and Jwtly strips the prefix and decodes the header and payload as pretty JSON. exp, iat and nbf are shown as local times with expired / not-yet-valid badges. Optional signature verify uses the browser’s Web Crypto API: HS256–512 with a shared secret, RS256–512 and ES256–512 with a PEM public key. No upload: the token, secret, and key never leave your device and are never written to the URL.
Typical debugging flow for a 401:
- Copy the
Authorizationheader value from DevTools → Network - Paste it into Jwtly
- Check
audagainst your API identifier andexp/nbfagainst the current time - Confirm the required
scopeor role is in the payload - If needed, verify the signature with the issuer’s public key
Chinese UI: Jwtly 中文
Command-line alternative
If you prefer the terminal, the payload is just base64url. For example:
echo "$TOKEN" | cut -d. -f2 | tr '_-' '/+' | base64 -d 2>/dev/null
You may need to add = padding for base64 -d to accept it. This also stays on your machine — just remember the token may now sit in your shell history.
Related privacy-first workflow
- New to the risks? Read Decode a JWT Without Sending the Token Anywhere.
- Large nested payload? Format and explore it locally with JSONly.
- Converting
expby hand? Epochly turns Unix timestamps into dates in your browser.
Bottom line
A bearer token is a password with an expiry date. Read its aud, exp, and scope to debug auth — but do it in a decoder that runs on your device, never one that sends the token to a server.