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 — 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, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
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.
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, and the Java Academy course includes 4 lessons in total. 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.
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; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
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