JWT Authentication
A JSON Web Token is a signed, self-contained credential of the form header.payload.signature that lets a server authenticate every request statelessly — no session storage required.
Learn JWT Authentication in our free Java course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.
Part of the free Java course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
Before You Start
You should know the basics of Spring Security — authentication, authorization, and the filter chain. A grasp of HTTP headers and Base64 encoding will help.
What You'll Learn
The Big Idea — A Tamper-Proof Festival Wristband
💡 Analogy: A JWT is like a festival wristband . When you check in, staff give you a wristband printed with your name and access level (the payload ) and seal it with a special tamper-evident strip (the signature ). After that, gate staff don't look you up in any database — they just glance at the wristband, confirm the seal is intact, and wave you through. That is stateless auth: the credential carries everything. But note: anyone can read what's printed on it, so it holds no secrets — and whoever physically holds the band gets in, which is why you don't lose it and why it expires.
Self-contained, verifiable by anyone with the key, readable by everyone — exactly a signed JWT.
1️⃣ The Structure — header.payload.signature
Three dot-separated Base64URL segments. The first two are just encoded JSON — let's decode them to prove the payload is not secret.
2️⃣ The Signature — Proving Integrity
The signature is an HMAC over header.payload using a secret key (HS256 = HMAC-SHA256). Recompute it and you can detect any tampering — change one byte of the payload and verification fails.
3️⃣ Validating Tokens in Spring Security
In Spring you add a custom OncePerRequestFilter to the chain. It reads the Authorization: Bearer ... header, validates the token, and populates the SecurityContext — with sessions set to STATELESS .
🧠 Quick Recall
Answer: header , payload , and signature , joined by dots and Base64URL-encoded.
Answer: yes — the payload is only encoded, not encrypted, so anyone can decode it. Keep secrets out of it.
Answer: in the HTTP header Authorization: Bearer <token> .
🎯 YOUR TURN — Validate Token Shape
Write isWellFormed(token) that returns true only for exactly three non-empty dot-separated parts.
🧩 MINI-CHALLENGE — Decode and Check Expiry
Base64URL-decode a payload, read its exp , and print ACTIVE or EXPIRED for two different "now" values.
Common Errors
- ❌ Putting secrets in the payload. It's only encoded, so anyone reads it. Fix: store only non-sensitive claims.
- ❌ Not verifying the signature. Trusting decoded claims invites forgery. Fix: always validate before trusting.
- ❌ Ignoring exp . Expired tokens get accepted forever. Fix: reject tokens past their expiry.
- ❌ Forgetting STATELESS session policy. Spring may still create sessions. Fix: set SessionCreationPolicy.STATELESS .
- ❌ Long-lived access tokens. A stolen token works for ages. Fix: short expiry + refresh tokens.
- ❌ Sending tokens over plain HTTP. They can be sniffed. Fix: require HTTPS.
Pro Tips
- 💡 Use a vetted library (e.g. JJWT or Spring's resource-server support) rather than hand-rolling JWT parsing.
- 💡 Validate issuer and audience claims too, not just the signature, to limit token reuse.
- 💡 Keep access tokens short and pair them with refresh tokens for a good UX/security balance.
- 💡 Add the JWT filter before UsernamePasswordAuthenticationFilter so authentication is set early.
📋 Quick Reference
Concept
Syntax / idea
Note
structure
header.payload.signature
3 Base64URL parts
header
alg, typ
e.g. HS256
payload
claims: sub, exp, iat
Encoded, not secret
signature
HMAC over header.payload
Integrity check
subject
"sub"
The user
expiry
"exp"
Unix seconds
transport
Authorization: Bearer ...
Per request
stateless
no server session
Scales well
spring filter
OncePerRequestFilter
Validates token
policy
STATELESS
No HTTP session
📚 Resources / Keep Learning
- 📘 RFC 7519 — JSON Web Token (JWT)
- 📗 JWT support — Spring Security docs
- 📗 Introduction to JSON Web Tokens (jwt.io)
❓ Frequently Asked Questions
🎉 Lesson Complete!
You now understand a JWT's header.payload.signature structure, why the payload is readable but tamper-evident, how stateless authentication works, and how a Spring Security filter validates a Bearer token on every request.
Next up: Testing with @SpringBootTest & MockMvc — verifying your controllers and beans automatically.
Practice quiz
How many parts does a JWT have, and how are they separated?
- Three parts joined by dots: header.payload.signature
- Two parts joined by a colon
- One Base64 string
- Four parts joined by slashes
Answer: Three parts joined by dots: header.payload.signature. A JWT is header.payload.signature — three Base64URL segments separated by periods.
What does the JWT signature provide?
- Encryption of the payload
- Integrity — proof the token was not tampered with and came from a trusted issuer
- Compression
- The user's password
Answer: Integrity — proof the token was not tampered with and came from a trusted issuer. The signature lets the server verify the token's integrity and authenticity; a signed JWT is not encrypted by default.
Is the payload of a standard (signed, not encrypted) JWT secret?
- Yes, it is encrypted
- Yes, only the server can read it
- No, it is only Base64URL-encoded and anyone can read it
- It is hashed irreversibly
Answer: No, it is only Base64URL-encoded and anyone can read it. A signed JWT's claims are merely Base64URL-encoded, so never put secrets in the payload — anyone can decode it.
What does 'stateless authentication' mean with JWTs?
- The server stores every session in memory
- Tokens never expire
- The client stores nothing
- The server keeps no session; the self-contained token carries the identity each request
Answer: The server keeps no session; the self-contained token carries the identity each request. The token itself holds the claims, so the server needn't store server-side session state — it just verifies the signature.
How is a JWT typically sent on each request?
- As a URL query parameter named jwt
- In the Authorization header as 'Bearer <token>'
- In a cookie named PHPSESSID only
- In the request body as XML
Answer: In the Authorization header as 'Bearer <token>'. The convention is the HTTP header: Authorization: Bearer eyJ... so a filter can extract and validate it.
In Spring Security, where do you validate the JWT on incoming requests?
- In the controller method body
- In application.properties
- In a custom filter added to the SecurityFilterChain (e.g. a OncePerRequestFilter)
- In the database trigger
Answer: In a custom filter added to the SecurityFilterChain (e.g. a OncePerRequestFilter). A custom authentication filter reads the Bearer token, validates it, and sets the Authentication in the SecurityContext.
Which JWT claim conventionally marks the subject (the user)?
- sub
- alg
- color
- ttl
Answer: sub. The 'sub' (subject) registered claim identifies the principal; 'exp' is expiry, 'iat' is issued-at.
Which claim makes a token expire?
- sub
- iss
- exp
- jti
Answer: exp. 'exp' (expiration time) is a Unix timestamp after which the token must be rejected as expired.
A key advantage of stateless JWT auth for scaling is...
- Tokens are encrypted by default
- It removes the need for HTTPS
- Any server instance can verify a request without a shared session store
- Tokens can never be stolen
Answer: Any server instance can verify a request without a shared session store. Because verification needs only the signing key, requests can hit any node without sticky sessions or a central session DB.
Why should JWTs be sent only over HTTPS and kept short-lived?
- To make them longer
- Because a stolen Bearer token grants access until it expires
- To enable Base64 encoding
- Because HTTP is faster
Answer: Because a stolen Bearer token grants access until it expires. A signed token is a bearer credential: whoever holds it is trusted, so transport encryption and short expiry limit the damage of theft.
Continue this course
- Previous: Spring Security Basics
- Next: Testing with @SpringBootTest & MockMvc