DeveloperSecurityAuthentication

How JWT Authentication Works

JSON Web Tokens explained: header, payload, signature, claims, signing algorithms, access and refresh tokens, validation rules, browser storage tradeoffs, and the security mistakes that break auth systems.

9 min read

TL;DR - Key Points

JWT meaningJWT stands for JSON Web Token, a compact URL-safe format for representing claims between two parties.
Three partsA JWT usually has header.payload.signature. Header and payload are Base64URL-encoded JSON; the signature protects integrity.
Signed, not encryptedMost JWTs are signed JWS tokens, not encrypted JWE tokens. Anyone holding the token can decode and read header and payload.
ClaimsClaims are payload fields such as sub, iss, aud, exp, nbf, iat, jti, roles, and scopes.
Access tokenA short-lived bearer token sent with API requests, commonly in the Authorization: Bearer header.
Refresh tokenA longer-lived credential used to obtain new access tokens. It should be stored and rotated more carefully than access tokens.

What Is a JWT?

A JSON Web Token is a compact, URL-safe token format used to represent claims between parties. In authentication systems, a server or identity provider issues a JWT after login. The client then sends that token with API requests, and the API verifies it before trusting the request.

A typical JWT looks like three long text segments separated by dots: header.payload.signature. The header says what kind of token it is and which algorithm was used. The payload contains claims such as user ID, issuer, audience, expiry, roles, or scopes. The signature lets the server detect whether the header or payload was changed.

The most important security fact is simple: signed JWTs are not secret. The header and payload are encoded, not encrypted. If a token contains an email, role, tenant ID, or internal identifier, anyone holding the token can decode and read it. Never put passwords, API keys, private notes, or sensitive personal data in a normal signed JWT.

JWTs are useful because APIs can verify tokens without calling a session database on every request. That statelessness is powerful, but it creates tradeoffs around revocation, logout, key rotation, and stale permissions.

The Three Parts of a JWT

PartExamplePurpose
Header{ "alg": "RS256", "typ": "JWT" }Describes token type and signing algorithm.
Payload{ "sub": "user_123", "exp": 1767225600 }Contains claims about the subject, issuer, audience, expiry, roles, or scopes.
SignatureSign(base64url(header) + '.' + base64url(payload))Lets the server detect tampering when it verifies the token.

Base64URL decoding a JWT is safe for inspection, but it does not prove the token is real. Trust begins only after signature and claim validation.

Common JWT Claims

ClaimNameMeaningExample
issIssuerWho issued the tokenhttps://auth.example.com
subSubjectWho the token is aboutuser_123
audAudienceWho should accept the tokenapi://billing-service
expExpiration TimeToken must not be accepted after this Unix timestamp1767225600
nbfNot BeforeToken must not be accepted before this time1767222000
iatIssued AtWhen the token was issued1767220200
jtiJWT IDUnique token identifier, useful for replay detection or revocation lists01HZY...

The time claims use Unix timestamps in seconds. Do not compare exp to JavaScript Date.now() directly unless you divide Date.now() by 1000.

JWT Authentication Flow

StepClientServer / API
1. LoginSends username/password or OAuth codeValidates credentials with identity provider or user database
2. Issue tokensReceives access token and maybe refresh tokenSigns JWT with configured algorithm, expiry, issuer, audience, and subject
3. API requestSends Authorization: Bearer <access_token>Extracts token before route handler
4. Verify tokenNo actionChecks signature, exp, nbf, iss, aud, algorithm, and required claims
5. AuthorizeReceives result or 403Uses scopes/roles/permissions to decide whether action is allowed
6. RefreshUses refresh token when access token expiresValidates refresh token, rotates it, and issues new access token

Signing Algorithms

AlgorithmTypeKey ModelBest UseRisk
HS256Symmetric HMACSame secret signs and verifiesSimple first-party systems where every verifier can safely know the secretSecret leakage lets attackers mint tokens.
RS256Asymmetric RSAPrivate key signs, public key verifiesDistributed systems, OAuth/OIDC, APIs verifying tokens from an auth serverKey rotation and JWKS caching must be handled carefully.
ES256Asymmetric ECDSAPrivate key signs, public key verifiesModern compact signatures when library support is matureImplementation quality and operational familiarity matter.
noneNo signatureNo cryptographic verificationAlmost never for authenticationMust not be accepted for auth tokens unless explicitly designed for a safe non-auth context.

A verifier should know which algorithm it expects before reading the token. Do not let an attacker choose the verification rules through the token header.

Access Tokens vs Refresh Tokens

FactorAccess TokenRefresh Token
PurposeAuthorize API requestsGet new access tokens
LifetimeShort, often minutesLonger, often days or weeks
Sent to APIsYes, on most authenticated requestsNo, only to token refresh endpoint
Storage priorityReduce theft and exposureProtect heavily; rotate and revoke on reuse
RevocationHarder if stateless and short-livedUsually server-tracked for rotation and logout
If stolenAttacker can call APIs until expiryAttacker may mint new access tokens unless reuse detection stops it

Server-Side JWT Validation Checklist

CheckWhy It MattersIf It Fails
Parse formatA normal signed JWT has exactly three dot-separated segments.Reject malformed tokens before deeper processing.
Allowlist algorithmDo not trust alg blindly from the token header.Reject unexpected algorithms and never auto-switch key types.
Verify signatureProves header and payload were not changed after signing.Reject on any verification error.
Validate exp and nbfPrevents expired or not-yet-valid tokens from being accepted.Reject or allow only small clock skew.
Validate issConfirms the trusted issuer created the token.Reject tokens from unknown issuers.
Validate audPrevents a token meant for one API being replayed at another.Reject audience mismatch.
Validate scopes/rolesAuthentication is not the same as authorization.Return 403 when identity is valid but permission is missing.
Check revocation when neededLogout, compromise, or refresh-token reuse may require server-side state.Reject revoked jti/session identifiers.

Browser Storage Options

StorageStrengthsWeaknesses
HttpOnly Secure cookieNot readable by JavaScript; works well with browser appsNeeds CSRF protections and careful SameSite/domain settings
Memory onlyToken disappears on refresh/close; less persistent theft riskRequires refresh strategy and can complicate UX
localStorageSimple and persistentReadable by JavaScript, so XSS can steal tokens
sessionStorageClears when tab/session endsStill readable by JavaScript and vulnerable to XSS
Native mobile secure storageCan use OS-backed secure storageStill needs device compromise and refresh-token rotation considerations

Storage is a threat-model decision. Whatever you choose, XSS prevention, HTTPS, cookie flags, CSRF strategy, and short-lived access tokens matter.

Common JWT Vulnerabilities

IssueProblemFix
Decoding without verifyingThe app trusts payload fields after Base64URL decoding only.Always verify the signature and registered claims server-side.
Algorithm confusionThe verifier accepts unexpected alg values or mixes symmetric/asymmetric keys incorrectly.Hard-code an algorithm allowlist and use libraries safely.
Long-lived access tokensA stolen token remains useful for too long.Use short access-token lifetimes and refresh-token rotation.
Secrets in payloadJWT payload is readable by anyone who has the token.Store only non-sensitive claims or use encrypted JWE where appropriate.
Missing audience checksA token issued for one service is accepted by another.Validate aud for every API.
No revocation strategyLogout or compromise cannot invalidate already-issued stateless tokens.Use short expiry, jti/session records, refresh-token rotation, or introspection where needed.
Storing tokens in localStorage with XSSMalicious JavaScript can read and exfiltrate tokens.Prevent XSS, consider HttpOnly cookies or memory storage, and use CSP.

JWT Debugging Quick Reference

SymptomLikely CauseWhat to Check
User is logged out immediatelyexp is in the past or clock skew is wrongDecode exp, compare to current Unix seconds, verify server clock.
API returns 401Signature invalid, token expired, wrong issuer, wrong audienceCheck verification logs, iss, aud, kid, alg, and expiry.
API returns 403Token is valid but missing permissionInspect scopes, roles, tenant ID, and route authorization policy.
Works locally, fails in productionDifferent issuer, audience, public key, cookie domain, or HTTPS settingCompare environment config and JWKS URL.
Refresh works once then failsRefresh-token rotation or reuse detection issueConfirm client stores the newest refresh token after every refresh.
Token accepted by wrong serviceAudience validation missingAdd strict aud validation per API.

Frequently Asked Questions

Is a JWT encrypted?

Usually no. The common JWT used in web authentication is a signed JWS. The header and payload are Base64URL-encoded, which means they are easy to decode. Signing protects integrity, not confidentiality. Use JWE or avoid putting sensitive data in the token if confidentiality is required.

Is decoding a JWT enough to trust it?

No. Decoding only reads the JSON. Anyone can create a fake header and payload. A backend must verify the signature and validate claims like exp, iss, aud, and nbf before trusting the token.

Where should JWTs be stored in a browser?

There is no one perfect answer. HttpOnly Secure cookies reduce JavaScript token theft but require CSRF defenses. Memory storage reduces persistence but complicates refresh. localStorage is simple but vulnerable to XSS token theft. Choose based on your threat model.

How long should an access token live?

Many systems use short lifetimes, often minutes, because access tokens are bearer credentials. The exact value depends on risk, UX, and whether refresh-token rotation and revocation are implemented.

What is the difference between authentication and authorization?

Authentication proves who the caller is. Authorization decides what that caller may do. A valid JWT can authenticate a user, but the API still needs to check scopes, roles, tenant access, and object-level permissions.

Can JWTs be revoked?

Pure stateless JWT access tokens are difficult to revoke before expiry. Common patterns include short access-token lifetimes, refresh-token rotation, server-side session IDs, jti deny-lists, key rotation for emergency invalidation, or token introspection.

What is JWKS?

JWKS stands for JSON Web Key Set. It is a published set of public keys that APIs can use to verify tokens signed by an authorization server. The token header often includes kid, a key ID that helps the verifier pick the right public key.

Should JWT contain roles?

It can, but be careful. Roles and scopes inside JWTs can become stale until the token expires. For high-risk permissions, check server-side authorization state or keep access tokens short.

Related Concepts

Related Tools

JWT Decoder

Decode JWT headers and payloads locally and inspect standard claims.

Open Tool

JWT Token Validator

Validate JWT structure and debug token problems during development.

Open Tool

JWT Encoder Signer

Create and sign test JWTs for local development workflows.

Open Tool

Timestamp to Date Converter

Convert exp, iat, and nbf Unix timestamps into readable dates.

Open Tool