What is a Cognito JWT?
When a user signs in to a Cognito user pool, AWS issues three JSON Web Tokens: an
id_token (identity claims like email and name), an access_token
(used to authorize API calls), and a refresh_token (opaque; used to mint new
id and access tokens). All three are signed by your user pool's private key, and the matching
public JWKS is published at
https://cognito-idp.<region>.amazonaws.com/<user-pool-id>/.well-known/jwks.json.
The header and payload are base64url-encoded JSON — which is why decoding them requires
nothing more than base64 math and a JSON parser.
When should I use this tool?
- Debugging 401s. Your API is rejecting a token. Paste it here, check
token_use,exp, and whetheraudorclient_idis set before you go digging through CloudWatch. - Verifying group membership. The frontend thinks the user is an admin, the
backend disagrees. Decode the token and check the
cognito:groupsarray directly. - Auditing what your SDK is sending. If Amplify, a hand-rolled fetch wrapper, or a mobile SDK is attaching the wrong token type, this surfaces the mismatch immediately.
- Explaining Cognito to a teammate. Easier to show the decoded shape than to describe it in words.
Cognito JWT gotchas this tool flags for you
client_id vs aud
The single most common source of Cognito token-validation bugs. Cognito id tokens put
the App Client ID in the standard aud claim. Cognito access tokens put it
in a non-standard client_id claim and leave aud off entirely. Many
JWT libraries validate only the aud claim by default — which means access-token
validation silently accepts tokens from any app client. We surface whichever one is present and
nudge you toward the correct validation path.
token_use mismatches
Every Cognito JWT has a token_use claim set to either access,
id, or refresh. If you're calling an API Gateway authorizer with
the id_token but the authorizer expects the access_token, the audience check fails in a
confusing way. When you paste an id_token, we surface that and remind you the access token is
usually what you want for API authorization.
Clock skew
If iat is more than a minute in the future, one of the machines involved has clock
drift. This is surprisingly common in local dev when WSL or a VM has stale NTP. We flag it so
you don't chase a validation-logic red herring.
Missing profile claims on id_token
If your User Pool's attribute mapping doesn't include email or name, the id_token arrives without them. Downstream code that assumes they're present breaks silently. This tool highlights which standard profile claims are actually present.
How decoding works (and why it's safe to paste production tokens)
A JWT is three base64url-encoded strings separated by dots: header, payload, signature. The header and payload are plain JSON once decoded — no key, no network call, no cryptography required. That's exactly what happens when you click Decode: the browser does the base64 and JSON.parse, then renders the result. The token never touches our servers and isn't logged. Open your browser's dev tools Network tab to confirm there's no request made during decode. Signature validation, which does require the user pool's public key, is a server-side responsibility and isn't performed here — for debugging contents, decoding is enough.
Frequently asked questions
Does this tool validate my token's signature?
No. Signature validation requires the user pool's JWKS and has to be done server-side against the keys pinned for your issuer. Decoding reveals what a token says; validating proves what a token is. They're complementary, and for "why is this thing getting rejected" debugging, decode-only is usually enough.
Why is my access token missing an email claim?
Cognito access tokens only carry authorization-relevant claims. Profile data (email, name,
phone, custom attributes) lives in the id_token. If you need the user's email on the server,
either pass the id_token along with the access token, call Cognito's GetUser API
using the access token, or include the email in an API Gateway custom authorizer's output
context.
Is it really safe to paste a production token here?
Yes. The token is decoded entirely client-side in JavaScript. No request is made to our server during decoding, and nothing is stored in localStorage or cookies. Your browser's Network tab will show zero requests when you click Decode.
Why is my token expired but my app still works?
SDKs like Amplify silently refresh access and id tokens when they near expiry. The token you just pasted may be an older one that your SDK already rotated away from. Grab the current one from your SDK's storage (usually sessionStorage or a hook/store in your app) rather than an older snapshot.
What about refresh tokens?
Refresh tokens from Cognito are opaque — they're not JWTs and there's nothing meaningful to decode. If you paste one, you'll get a "JWT must have three dot-separated segments" error. That's expected.