What is JWT authentication and how does it work?
Quick Answer
A JWT is a signed token with three base64url parts — header, payload (claims), signature. After login the server issues one; the client sends it as Authorization: Bearer <token> on each request; the API validates the signature and expiry and builds the user from the claims — no server-side session lookup.
A JWT is a signed token with three parts — header, a payload of claims, and a signature. When a user logs in, the server creates one and the client sends it on every request in the Authorization: Bearer header. The API validates the signature, issuer, audience and expiry, then builds the ClaimsPrincipal straight from the claims — there's no session lookup, which is why it scales. The trade-off is revocation: you can't invalidate a token before it expires, so I keep access tokens short-lived and use refresh tokens. And it's signed, not encrypted, so no secrets go in the payload.
- Structure:
header.payload.signature. The payload holds claims (sub,exp,role, custom). It is signed, not encrypted — don't put secrets in it. - Signing: symmetric (HMAC with a shared secret) or asymmetric (RSA/ECDSA — the IdP signs with a private key, APIs verify with the public key from a JWKS endpoint).
- Validation:
AddAuthentication().AddJwtBearer(...)checks issuer, audience, lifetime and signature. - Stateless — nothing to look up, which scales well, but you can't easily revoke a token before it expires. Mitigate with short lifetimes + refresh tokens, or a denylist for logout.
- Storage on the client: memory or an httpOnly cookie is safer than
localStorage(XSS).
- Putting sensitive data in the payload — a JWT is signed, not encrypted; anyone can decode it.
- Storing the token in
localStorage, exposing it to any XSS on the page. - Very long token lifetimes with no refresh-token strategy, so a leaked token is valid for hours.
- Not validating issuer and audience — only checking the signature.