What a JWT is
A JSON Web Token is three base64url encoded parts joined by dots: a header, a payload and a signature. The payload typically holds a user ID, often an email address and roles, and an expiry time in the exp claim.
Two properties matter when you are about to paste one somewhere:
- It works for whoever has it. An API that accepts a JWT in an
Authorization: Bearerheader or a cookie does not know who is sending it. A copied token works like the original until it expires, unless the server keeps a list of revoked tokens. - It is signed, not encrypted. The signature stops anyone from changing the payload, but anyone can read it. An expired token still shows the user's ID, email and roles. Encrypted tokens (JWE) exist, but they are much less common.
Refresh tokens are worse: they last longer and can be exchanged for new access tokens.
Where JWTs leak
- Debug logs that print request headers.
- HAR files and Copy as cURL output from browser DevTools, which include headers and cookies.
- URLs: some sign in flows return tokens in the redirect URL, which can end up in browser history and, when the token is in the query string, in server logs.
- Screenshots of DevTools, local storage or cookies.
- Bug reports and AI chats where someone pasted the token to ask what is wrong with it.
Decode a JWT without pasting it into a website
You do not need an online decoder to read the payload. With Node.js or Python:
node -e "console.log(Buffer.from(process.argv[1].split('.')[1], 'base64url').toString())" "$TOKEN"
python3 -c "import base64,sys; p=sys.argv[1].split('.')[1]; print(base64.urlsafe_b64decode(p + '=' * (-len(p) % 4)).decode())" "$TOKEN"
Both print the payload JSON. Neither checks the signature, which is fine when you only want to read it.
Mask JWTs before sharing
Before highlights what PasteSafe finds, After is its exact output:
GET /v1/invoices HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI0ODIxIiwiZW1haWwiOiJqYW5lLmRvZUBleGFtcGxlLmNvbSIsInJvbGUiOiJhZG1pbiJ9.FakeSignatureForDocs0nly7fK2mZpL9wR3nB8vT1y
Cookie: refresh_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI0ODIxIiwidHlwIjoicmVmcmVzaCJ9.FakeRefreshSignatureForDocs0nly9wR3nB8vT1yC; theme=dark
HTTP/1.1 302 Found
Location: https://app.example.com/callback?id_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI0ODIxIiwiYXVkIjoiYmlsbGluZy13ZWIifQ.FakeIdTokenSignatureForDocs0nlyQ2mZpL9wR3n&state=af0ifjsldkj
decoded: {"sub":"4821","email":"jane.doe@example.com","role":"admin"}GET /v1/invoices HTTP/1.1
Host: api.example.com
Authorization: Bearer JWT_1
Cookie: refresh_token=JWT_2; theme=dark
HTTP/1.1 302 Found
Location: https://app.example.com/callback?id_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI0ODIxIiwiYXVkIjoiYmlsbGluZy13ZWIifQ.FakeIdTokenSignatureForDocs0nlyQ2mZpL9wR3n&state=af0ifjsldkj
decoded: {"sub":"4821","email":"EMAIL_1","role":"admin"}The token in the header and the refresh token cookie each get their own placeholder. The token in the redirect URL does not: PasteSafe can miss a JWT in a query string when another parameter follows it, so shorten such URLs by hand. On the decoded payload line only the email is masked. The user ID and role stay, so remove decoded payloads by hand if those matter.
- Paste the log, request or HAR excerpt into PasteSafe.
- JWTs become
JWT_1, other Bearer tokensBEARER_TOKEN_1, and values under names liketokenorsecretbecomeSECRET_1. - Read the result and copy it.
If a valid token leaked
- Revoke the refresh token and end the session in your identity provider, if it supports that. The access token itself may keep working until it expires.
- If tokens cannot be revoked one by one, rotating the signing key is the immediate fix. It invalidates every token signed with that key, so everyone has to sign in again.
- Keep access token lifetimes short, so a leaked token stops working soon.
What PasteSafe does not catch
- A JWT in a URL query string with another parameter after it, like the redirect URL above.
- A JWT split across lines, for example in wrapped log output.
- Decoded payloads: user IDs, names and roles in plain JSON.
- Opaque session tokens such as a
sessionidcookie with a hex value, sent together with other cookies.
Questions
Is it safe to share a JWT token?
Not while it is valid. Anyone who has it can use it until it expires, and anyone can read its payload even after that. Mask it before sharing a log, and share only the decoded claims you need.
Can a JWT be decoded without the secret?
Yes. The header and payload are only base64url encoded, so anyone can read them. The secret or private key is needed to create a valid signature, not to read the token.
Does an expired JWT still expose data?
Yes. It no longer grants access, but the payload still shows whatever the issuer put in it, such as the user ID, email address and roles.
Can I revoke a JWT?
Not on its own. A server accepts a valid JWT until it expires unless it keeps a list of revoked tokens or the signing key is rotated. Revoking the refresh token stops new access tokens from being issued.