Developer Tools

JWT Decoder

Decode and inspect JSON Web Tokens instantly. View the header, payload claims, and signature. Check expiration and standard claims at a glance. 100% private: your token never leaves the browser.

Last updated

Header & Payload
Expiry Check
Claims Table
100% Private
Our networkfavorit5The 5 worth buying.Top fives, comparisons and what reviewers say.See the top 5s
JWT
JWT Decoder & Inspector
Decode · Inspect claims · Check expiry · 100% local
Paste a JWT token above to decode it

Decoding Is Not Verifying

A JWT is three Base64url parts joined by dots, header.payload.signature, and anyone can read the first two without a key. Paste a token above to see its header and claims as JSON, with exp, iat and nbf turned into dates. This tool decodes only: it does not verify the signature, so never trust a token just because it decodes.

The header and payload of a signed JWT are only encoded, not encrypted, so they can be read without any key. Whether the token is genuine depends on the signature, and checking it needs the issuer's secret or public key. This page does the first job only. Decoding runs in your browser; the token is not sent anywhere.

A Token Taken Apart

This is the well-known example token (line breaks added):

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

  • Header (36 characters) decodes to {"alg":"HS256","typ":"JWT"}.
  • Payload (74 characters) decodes to {"sub":"1234567890","name":"John Doe","iat":1516239022}. 74 is not a multiple of 4, so a decoder adds == before decoding; JWTs always drop the padding.
  • iat 1516239022 is 18 January 2018, 01:30:22 UTC.
  • Signature (43 characters) is an HMAC-SHA256 of the first two parts joined by a dot. It checks out only with the secret it was made with, in this case your-256-bit-secret.

Because the payload is only Base64url, a JWT is no place for passwords or personal data you would not show the user.

Registered Claims Quick Reference

ClaimMeaningExampleWhat the server should check
issIssuerhttps://auth.example.comExactly matches the issuer you trust
subSubjectuser_123456Identifies the user or client
audAudiencehttps://api.example.comContains your own API's identifier
expExpiration time1747622400Current time is before it
nbfNot before1716000000Current time is at or after it
iatIssued at1716000000Not in the future; optional maximum age
jtiJWT ID8f14eb8d-97f9-...Not seen before, if you block replays
alg (header)Signing algorithmHS256, RS256, ES256Is on your allow list; never accept none
kid (header)Key IDkey-123Picks the key from your own key set

The examples come from the tool's sample token, whose exp of 1747622400 is 19 May 2025, 02:40 UTC, which is why the sample shows as expired.

Timestamps Are Seconds, Not Milliseconds

exp, nbf and iat are NumericDate values: whole seconds since 1 January 1970 UTC. JavaScript's Date.now() returns milliseconds, so a common bug is writing exp: Date.now() + 3600000. The result has 13 digits, and read as seconds, 1747622400000 lands in the year 57349; the token effectively never expires. Use Math.floor(Date.now() / 1000) + 3600 for one hour. As a quick check, a current timestamp in seconds has 10 digits.

Decode Errors and Their Causes

  • "Must have at least two parts": only part of the token was copied. A signed JWT has exactly two dots.
  • Five parts: this is an encrypted JWE, not a signed JWT. The payload cannot be read without the decryption key.
  • Invalid header or payload: a character was lost or changed when copying, or the string is an opaque access token that only looks like a JWT. Not every OAuth access token is a JWT.
  • "Bearer" or quotes around it: the tool now strips a leading Bearer and surrounding quotes for you.

JWT parts use the URL-safe Base64 alphabet; you can decode a single part in the Base64 decoder too, and turn exp values into dates with the Unix timestamp converter.

Method and sources. Token structure and registered claims follow RFC 7519 (JSON Web Token) and RFC 7515 (JSON Web Signature, including base64url without padding). Security checks follow RFC 8725 (JWT Best Current Practices). The example signature was checked with Node.js crypto HMAC-SHA256, and every date on this page was converted from its timestamp in Node.js.

JWT Guide

JWT (JSON Web Token) is an open standard (RFC 7519) for securely transmitting information between parties as a compact, URL-safe string. A JWT consists of three Base64url-encoded parts separated by dots: header.payload.signature. The header describes the token type and signing algorithm. The payload contains claims (statements about the user and metadata). The signature verifies the token has not been tampered with. JWTs are used for authentication (stateless sessions: the server doesn't need to store session state), API authorization (OAuth 2.0 Bearer tokens), and information exchange between microservices.

Claims are statements encoded in the JWT payload. Standard registered claims (all optional but recommended): iss (Issuer): who issued the token. sub (Subject): who the token is about, usually a user ID. aud (Audience): who the token is intended for. exp (Expiration Time): Unix timestamp after which the token is invalid. nbf (Not Before): Unix timestamp before which the token must not be accepted. iat (Issued At): when the token was issued. jti (JWT ID): unique identifier for the token, useful for preventing replay attacks. Public claims are registered in the IANA JWT Claims Registry. Private claims are custom, application-specific.

No. Decoding simply Base64url-decodes the header and payload: anyone can do this, no secret needed. This tool decodes but does not verify. Verification checks the signature using the secret key (for HMAC: HS256, HS384, HS512) or the public key (for RSA: RS256, RS512, and EC: ES256, ES512). Verification ensures the token was issued by a trusted party and has not been tampered with. A decoded but unverified JWT should never be trusted for authorization decisions. Always verify the signature server-side using a library like jsonwebtoken (Node.js), PyJWT (Python), or java-jwt (Java).

HS256 (HMAC-SHA256): uses a single shared secret for both signing and verification. Simple but the verifier must know the secret. Use when the issuer and verifier are the same system. RS256 (RSA-SHA256): uses a private key to sign and a public key to verify. The public key can be shared openly. Use when multiple services need to verify tokens issued by a central auth server. ES256 (ECDSA-SHA256): like RS256 but uses elliptic curve cryptography for smaller key and signature sizes. More efficient than RSA at equivalent security levels. RS256 and ES256 are preferred for production systems because the signing key never needs to be shared. None algorithm (no signature) should never be accepted in production.

This tool decodes entirely in your browser. No JWT is sent to any server, logged, or stored. You can disconnect from the internet after the page loads and it still works. However, you should still be careful with production tokens because: (1) tokens may contain sensitive user data in the payload, (2) if the token is still valid, anyone with it can use it. Best practice for debugging: use a test environment token or invalidate the token after debugging. The signature itself cannot be verified here (no secret key), so there is no risk of key exposure. Corporate IT policies may restrict pasting tokens into any external tool: check your organization's guidelines.

JWKS (JSON Web Key Set) is a public endpoint (typically at /.well-known/jwks.json) that exposes the public keys used to verify JWTs. OAuth 2.0 providers (Auth0, Okta, Google, AWS Cognito) all publish a JWKS endpoint. Verification flow: (1) get the kid (Key ID) from the JWT header, (2) fetch the matching public key from the JWKS endpoint, (3) verify the JWT signature using that key. This allows key rotation without redeploying services. Libraries like jwks-rsa (Node.js) cache keys and handle rotation automatically. The alg in the JWKS must match the alg in the JWT header; always validate this to prevent algorithm confusion attacks.

Key vulnerabilities to be aware of: Algorithm confusion: an attacker changes the alg header from RS256 to HS256 and signs with the public key as the HMAC secret. Fix: always explicitly specify the expected algorithm. None algorithm: setting alg: none to bypass signature verification. Fix: reject tokens with alg: none. Weak secrets: HS256 with short secrets can be brute-forced. Fix: use secrets of at least 256 bits. Missing validation: not checking exp, iss, or aud. Fix: always validate all relevant claims. Sensitive data in payload: the payload is encoded, not encrypted. Fix: never store passwords or private data in JWT payload; use JWE (JSON Web Encryption) if encryption is needed.

JavaScript (browser): JSON.parse(atob(token.split('.')[1].replace(/-/g,'+').replace(/_/g,'/'))). Node.js: const [h,p] = token.split('.').slice(0,2).map(p => JSON.parse(Buffer.from(p,'base64url'))). Python: import base64, json; json.loads(base64.urlsafe_b64decode(token.split('.')[1]+'==')). For production, always use a library that also verifies the signature: Node.js jsonwebtoken, Python PyJWT, Go golang-jwt/jwt, Java jjwt, .NET System.IdentityModel.Tokens.Jwt. Decoding without verification is only appropriate for debugging and display purposes, never for authorization.

Session cookies store a session ID on the client; the server maintains session state (in memory or a database). Pros: easy to invalidate, smaller cookie size. Cons: requires server-side storage, doesn't scale horizontally without a shared session store (Redis). JWTs store all information in the token itself; the server is stateless. Pros: scales easily, works across microservices and domains (CORS-friendly), no database lookup per request. Cons: cannot be easily revoked before expiry (requires a blocklist), larger token size, sensitive data is in the payload. JWT is not inherently more secure than cookies. Use HTTP-only, Secure, SameSite cookies to store JWTs in browser environments to prevent XSS access to the token.

Short-lived access tokens (15 minutes to 1 hour) reduce risk if stolen but require frequent re-authentication. The refresh token pattern solves this: issue a short-lived access token (JWT, used for API calls) and a long-lived refresh token (opaque or JWT, stored securely). When the access token expires, the client sends the refresh token to a dedicated endpoint to get a new access token without re-entering credentials. Refresh tokens should be: stored in HTTP-only cookies (not localStorage), rotated on each use (refresh token rotation), revocable server-side (stored in database), and have a longer but finite expiry (days to weeks). This pattern is used by Auth0, Okta, Google OAuth, and most modern auth systems.

No. It decodes the header and payload but does not check the signature, so a forged or modified token decodes just as cleanly as a real one. Verify on your server with a maintained library and a fixed algorithm list, for example jwt.verify(token, secret, { algorithms: ['HS256'] }) in the Node.js jsonwebtoken package, and check exp, iss and aud at the same time.

Seconds. RFC 7519 defines exp, nbf and iat as NumericDate, the number of seconds since 1 January 1970 UTC. A 10-digit value such as 1747622400 is correct; a 13-digit value means milliseconds were used by mistake, which pushes the expiry tens of thousands of years into the future.