JWT + OAuth2 + OIDC + PKCE Complete small Guide
1. Authentication Fundamentals
Every secure application needs answers to two questions:
- Authentication - "Who are you?"
Example: User enters username, password, MFA. System verifies identity. Result: User is Bhargav. - Authorization - "What are you allowed to do?"
Example: User: Bhargav. Permissions:READ_ORDERS,CREATE_ORDER,DELETE_ORDER.
Authentication happens first. Authorization happens after.
Authentication
|
v
Authorization
2. Traditional Session-Based Authentication (Stateful)
Before JWT, applications commonly used sessions.
Flow:
- User logs in:
Browser --> username/password --> Server - Server creates:
Session ID = abc123.
Stores in Database/Memory:abc123 -> { User: Bhargav, Role: ADMIN }. - Browser receives:
Cookie: SESSION_ID=abc123. - Every request: Browser sends
GET /orderswithCookie: SESSION_ID=abc123. - Server receives Session ID, searches session storage, finds user, allows request.
Problems with Sessions:
Server maintains state - The server must remember:
Session ID -> User Information.Scaling problem - Imagine multiple servers behind a load balancer:
- User logs in on Server A, session stored there.
- Next request goes to Server B - no session found.
Solutions:
- Sticky sessions
- Shared session database
3. JWT Authentication (Stateless)
JWT solves this by putting information inside the token.
JWT: JSON Web Token - a compact, signed representation of claims between two parties.
Example: eyJhbGciOiJIUzI1Ni...
JWT vs Session
- Session: Server stores user state:
Server -> Session ID -> User Data. - JWT: Token contains information:
JWT = Header + Payload + Signature.
Server does not need to store session information.
4. JWT Structure
A JWT has three parts: HEADER.PAYLOAD.SIGNATURE
Example: xxxxx.yyyyy.zzzzz
Part 1: Header
Contains metadata. Example:
{
"alg": "RS256",
"typ": "JWT"
}
Meaning: JWT uses RSA SHA256 algorithm.
Part 2: Payload
Contains claims. Example:
{
"sub": "12345",
"name": "Bhargav",
"role": "ADMIN",
"exp": 1788888888
}
Common claims:
| Claim | Meaning |
|---|---|
sub |
User identifier |
iss |
Token issuer |
exp |
Expiration time |
iat |
Issued time |
roles |
User permissions |
Important: JWT payload is NOT encrypted. Anyone can Base64 decode it.
Therefore never store: passwords, credit cards, secrets inside JWT.
Part 3: Signature
Signature proves: "This token was created by a trusted issuer and was not modified."
Example:
Authorization Server:
Header + Payload
|
Private Key
|
Signature
Final JWT: Header.Payload.Signature
5. Public Key and Private Key
JWT commonly uses asymmetric cryptography.
- Private Key - Secret. Only authorization server owns it (e.g., Okta Private Key). Used for signing JWT.
- Public Key - Can be shared (e.g., Spring Boot API uses Okta Public Key to verify).
Flow:
Okta Private Key
|
v
Sign JWT
|
v
Spring Boot Public Key
|
v
Verify JWT
6. How JWT Validation Works
Client sends: GET /orders with Authorization: Bearer JWT_TOKEN.
Spring Boot receives: HEADER.PAYLOAD.SIGNATURE and checks:
- Signature Validation - Spring calculates
Verify(Header + Payload, Public Key). If valid: token came from trusted issuer. - Expiration - Checks
expclaim (e.g.,"exp": 1788888888). - Claims - Example:
role = ADMINallowsDELETE /users.
7. Stateless Nature of JWT
JWT is called stateless because:
- Server does not store user session.
- Every request contains all required information.
Example:Request + JWT = enough information.
Benefits:
- Easy horizontal scaling
- Works well with microservices
- No central session storage
8. JWT Security Best Practices
Short-lived Access Tokens - Example: 5 minutes, 15 minutes, 1 hour.
Why? If stolen, attacker has limited time.
9. Refresh Token
Problem: If access token expires every 15 minutes, user must log in repeatedly.
Solution: Refresh token.
Flow:
Access Token expires
|
v
Refresh Token
|
v
Authorization Server
|
v
New Access Token
Example: Access Token: 15 minutes, Refresh Token: days/weeks.
10. OAuth2 Relationship With JWT
Important: OAuth2 does not require JWT.
- OAuth2 defines how to get access.
- JWT defines how to represent the token.
Together:
OAuth2
|
v
Access Token
|
v
JWT Format
11. OAuth2 Components
- Resource Owner - User.
- Client - Application requesting access (e.g., Angular Application).
- Authorization Server - Creates tokens. Examples: Okta, Google, Azure AD, Auth0.
- Resource Server - API protecting resources (e.g., Spring Boot API).
12. OAuth2 Production Flow
Architecture: Browser - Angular - Spring Boot API - Okta
Phase 1: Backend Startup
Spring Boot starts. Configuration: issuer-uri = https://okta.com/oauth2/default.
Spring calls: GET /.well-known/openid-configuration (a REST API).
Response:
{
"authorization_endpoint": "",
"token_endpoint": "",
"jwks_uri": ""
}
Spring learns: Where are public keys? How to validate tokens?
Phase 2: User Login
Browser opens https://myapp.com. Angular loads.
Angular checks: Do I have token? If no: redirect to Okta Login Page.
Phase 3: User Authentication
User enters Username, Password, MFA.
Important: Password goes to Okta, not to Angular or Spring Boot.
Phase 4: Authorization Code
Okta returns authorization_code. Example: callback?code=abc123.
Phase 5: Token Exchange
Application calls POST /token.
Okta returns: Access Token (JWT) + Refresh Token.
Phase 6: API Request
Angular sends GET /orders with Authorization: Bearer JWT.
Phase 7: Spring Validation
Spring verifies JWT signature using Okta Public Key. If valid: request allowed.
13. PKCE (Proof Key for Code Exchange)
Used mainly for: Angular, React, Mobile Apps (because they cannot store client_secret).
PKCE Memory Rule: Remember: CREATE - HIDE - PROVE
- Create - Angular creates
code_verifier(e.g.,ABC123_SECRET). - Hide - Creates
SHA256(code_verifier)โcode_challenge.
Sendscode_challengeto Okta. Keepscode_verifiersecret. - Prove - Later sends
authorization_code+code_verifier.
Okta checks:SHA256(verifier) == stored challenge. If match, issue JWT.
14. Implicit Flow (Old)
Old SPA flow:
Browser
|
v
Authorization Server
|
v
JWT Token Directly
|
v
Angular
Problem: Token exposed in browser. Risks:
- Browser history
- URL leaks
- XSS attacks
15. Token Storage Options
Local Storage - Example:
localStorage.setItem("token", jwt)
Pros: Simple, persistent.
Cons: Vulnerable to XSS.Session Storage - Removed when tab closes. Better than local storage but still accessible by JavaScript.
Secure HttpOnly Cookie - Example:
Cookie: SESSION=abc123; HttpOnly; Secure; SameSite
JavaScript cannot access it. More secure. Common with Backend For Frontend (BFF).
16. Modern Recommendation
For SPA applications: Use Authorization Code Flow + PKCE. Avoid Implicit Flow.
Summary
| Concept | Description |
|---|---|
| JWT | A signed token containing claims that allows stateless authentication and authorization. |
| Session | Stateful authentication where server stores user session information. |
| OAuth2 | Framework for delegated authorization. |
| OIDC | Authentication layer built on OAuth2. |
| Discovery Document | Metadata endpoint that provides OAuth endpoints and public keys. |
| PKCE | Security mechanism that prevents authorization code theft by proving that the same client started and completed authentication. |
Production SPA Flow:
Angular --> PKCE Login --> Okta --> JWT --> Spring Boot --> Verify Signature --> Allow Request
Comments
No comments yet. Start the discussion.