JWT: Structure, Creation, and Verification
Manually decode JWT structure, create signed tokens with a secret, and verify claims without frameworks.
JWT: Structure, Creation, and Verification is a free Java Academy lesson on CoddyKit. This is lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Java Academy learning path, and your progress syncs across the web and the CoddyKit app. The Java Academy course includes 4 lessons in total.
What Is a JWT?
JSON Web Token (JWT) is a compact, URL-safe token format for transmitting claims between parties. A JWT is signed (and optionally encrypted). It is self-contained — no database lookup needed to verify claims.
JWT Structure: Header.Payload.Signature
A JWT has three Base64URL-encoded parts separated by dots: header.payload.signature. The header specifies the algorithm. The payload contains claims. The signature verifies integrity.
// Example JWT:
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 <- header
// .eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIn0 <- payload
// .SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c <- signatureHeader and Payload Decoded
Decode each part with Base64URL to see the JSON. The payload contains "claims" — standard ones: sub (subject), iss (issuer), exp (expiration), iat (issued at).
// Header:
{ "alg": "HS256", "typ": "JWT" }
// Payload:
{ "sub": "user-42", "name": "Alice", "role": "ADMIN",
"iat": 1716000000, "exp": 1716003600 }Creating a JWT Manually (HS256)
Build header and payload JSON, Base64URL-encode each, concatenate with a dot, then compute HMAC-SHA256 of header.payload and append as the signature.
String header = Base64.getUrlEncoder().withoutPadding()
.encodeToString("{\"alg\":\"HS256\",\"typ\":\"JWT\"}".getBytes());
String payload = Base64.getUrlEncoder().withoutPadding()
.encodeToString("{\"sub\":\"user-42\",\"exp\":9999999999}".getBytes());
String sigInput = header + "." + payload;
byte[] sig = computeHmac(secretKey, sigInput);
String jwt = sigInput + "." + Base64.getUrlEncoder().withoutPadding().encodeToString(sig);Verifying a JWT Manually
Split on dots, decode header and payload, recompute HMAC over header.payload, compare to the signature, and check that exp is in the future.
String[] parts = jwt.split("\\.");
String sigInput = parts[0] + "." + parts[1];
byte[] expectedSig = computeHmac(secretKey, sigInput);
byte[] actualSig = Base64.getUrlDecoder().decode(parts[2]);
if (!MessageDigest.isEqual(expectedSig, actualSig)) throw new SecurityException("Invalid signature");
// Decode payload and check exp:
String payloadJson = new String(Base64.getUrlDecoder().decode(parts[1]));
// parse JSON and check exp > nowUsing java-jwt Library (Auth0)
The com.auth0:java-jwt library simplifies JWT creation and verification with a fluent API.
// Create:
Algorithm alg = Algorithm.HMAC256(secretKey);
String token = JWT.create()
.withSubject("user-42")
.withClaim("role", "ADMIN")
.withExpiresAt(Instant.now().plusSeconds(3600))
.sign(alg);
// Verify:
JWTVerifier verifier = JWT.require(alg).withIssuer("my-service").build();
DecodedJWT decoded = verifier.verify(token);
System.out.println(decoded.getSubject());HS256 vs RS256
HS256 uses a shared symmetric key — simple but both issuer and verifier must trust each other with the key. RS256 uses RSA: sign with private key, verify with public key — suitable for multi-service architectures where any service verifies without knowing the signing key.
Storing JWTs: HttpOnly Cookies vs localStorage
Store JWTs in HttpOnly cookies (not accessible from JS — prevents XSS theft) with Secure and SameSite=Strict flags. Avoid localStorage — XSS attacks can read it.
// Set JWT as HttpOnly cookie in Spring:
ResponseCookie cookie = ResponseCookie.from("jwt", token)
.httpOnly(true).secure(true).sameSite("Strict")
.path("/").maxAge(3600).build();
response.addHeader(HttpHeaders.SET_COOKIE, cookie.toString());Refresh Tokens
JWTs have short expiry (15 min). Refresh tokens (opaque, stored server-side) have longer expiry. The client exchanges a refresh token for a new JWT without re-authenticating.
JWT Revocation Challenge
JWTs are stateless — there is no built-in revocation. Use a short expiry + a blocklist of revoked JWT IDs (jti claim) in Redis to support logout before expiry.
// On logout, add the jti to a Redis blocklist with TTL = token expiry:
redis.set("revoked:" + jti, "1", ex, 3600);
// On verify, check blocklist:
if (redis.exists("revoked:" + decoded.getId())) throw new SecurityException("Token revoked");Spring Security JWT Integration
In Spring Security, implement JwtAuthenticationFilter extends OncePerRequestFilter to extract, verify, and set the SecurityContext from the JWT on each request.
String token = request.getHeader("Authorization").replace("Bearer ","");
DecodedJWT decoded = verifier.verify(token);
String userId = decoded.getSubject();
UsernamePasswordAuthenticationToken auth =
new UsernamePasswordAuthenticationToken(userId, null, authorities);
SecurityContextHolder.getContext().setAuthentication(auth);Quick Check
What is the key structural difference between HS256 and RS256 JWT signing?
Recap
JWT = header.payload.signature (Base64URL). Sign with HMAC (HS256) or RSA (RS256). Verify signature and exp claim. Store in HttpOnly cookies. Use short expiry + refresh tokens. Revoke via jti blocklist in Redis.
Learn Java with an AI tutor — free
Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.
- Courses
- 104
- Lessons
- 374
Frequently Asked Questions
Is the “JWT: Structure, Creation, and Verification” lesson free?
Yes — the full text of “JWT: Structure, Creation, and Verification” is free to read here on the web. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Java Academy course, upgrade to CoddyKit PRO. The Java Academy course includes 4 lessons in total.
What will I learn in “JWT: Structure, Creation, and Verification”?
Manually decode JWT structure, create signed tokens with a secret, and verify claims without frameworks. You practise Java Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Java Academy?
No prior experience is required. Java Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 4 of 4.
How long does the “JWT: Structure, Creation, and Verification” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Java Academy lesson?
Yes. Every Java Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Cryptographic Hashing with MessageDigest
- AES Symmetric Encryption
- HMAC-SHA256 for Message Integrity
- JWT: Structure, Creation, and Verification