DEV Community

Bhargav Patel
Bhargav Patel

Posted on

JWT + OAuth2 + OIDC + PKCE Complete small Guide

The flow will be:

  1. Authentication foundation
  2. Session vs JWT
  3. JWT deep dive
  4. JWT security
  5. Access/Refresh tokens
  6. OAuth2 relationship with JWT
  7. End-to-end production flow
  8. PKCE
  9. Storage strategies
  10. summary

1. Authentication Fundamentals

Every secure application needs answers to two questions:

Authentication

"Who are you?"

Example:

User enters:

username
password
MFA
Enter fullscreen mode Exit fullscreen mode

System verifies identity.

Result:

User is Bhargav
Enter fullscreen mode Exit fullscreen mode

Authorization

"What are you allowed to do?"

Example:

User:
Bhargav

Permissions:

READ_ORDERS
CREATE_ORDER
DELETE_ORDER
Enter fullscreen mode Exit fullscreen mode

Authentication happens first.

Authorization happens after.

Authentication
      |
      v
Authorization
Enter fullscreen mode Exit fullscreen mode

2. Traditional Session-Based Authentication (Stateful)

Before JWT, applications commonly used sessions.

Flow

User logs in:

Browser
   |
   | username/password
   |
   v
Server
Enter fullscreen mode Exit fullscreen mode

Server creates:

Session ID = abc123
Enter fullscreen mode Exit fullscreen mode

Stores:

Database / Memory

abc123
 |
 |
User:
Bhargav
Role:
ADMIN
Enter fullscreen mode Exit fullscreen mode

Browser receives:

Cookie:

SESSION_ID=abc123
Enter fullscreen mode Exit fullscreen mode

Every Request

Browser sends:

GET /orders

Cookie:
SESSION_ID=abc123
Enter fullscreen mode Exit fullscreen mode

Server:

Receive Session ID

        |
        v

Search session storage

        |
        v

Find user

        |
        v

Allow request
Enter fullscreen mode Exit fullscreen mode

Problems with Sessions

1. Server maintains state

The server must remember:

Session ID
      |
      v
User Information
Enter fullscreen mode Exit fullscreen mode

2. Scaling problem

Imagine multiple servers:

             Load Balancer

          /              \

     Server A          Server B
Enter fullscreen mode Exit fullscreen mode

User logs in:

Server A

Session stored here
Enter fullscreen mode Exit fullscreen mode

Next request:

Server B

No session found
Enter fullscreen mode Exit fullscreen mode

Solutions:

  • Sticky sessions
  • Shared session database

3. JWT Authentication (Stateless)

JWT solves this by putting information inside the token.

JWT:

JSON Web Token

It is a compact, signed representation of claims between two parties.

Example:

eyJhbGciOiJIUzI1Ni...
Enter fullscreen mode Exit fullscreen mode

JWT vs Session

Session

Server stores user state:

Server

Session ID
    |
    v
User Data
Enter fullscreen mode Exit fullscreen mode

JWT

Token contains information:

JWT

Header
+
Payload
+
Signature
Enter fullscreen mode Exit fullscreen mode

Server does not need to store session information.


4. JWT Structure

A JWT has three parts:

HEADER.PAYLOAD.SIGNATURE
Enter fullscreen mode Exit fullscreen mode

Example:

xxxxx.yyyyy.zzzzz
Enter fullscreen mode Exit fullscreen mode

Part 1: Header

Contains metadata.

Example:

{
 "alg":"RS256",
 "typ":"JWT"
}
Enter fullscreen mode Exit fullscreen mode

Meaning:

JWT uses RSA SHA256 algorithm
Enter fullscreen mode Exit fullscreen mode

Part 2: Payload

Contains claims.

Example:

{
 "sub":"12345",
 "name":"Bhargav",
 "role":"ADMIN",
 "exp":1788888888
}
Enter fullscreen mode Exit fullscreen mode

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 decode:

Base64 decode
Enter fullscreen mode Exit fullscreen mode

Therefore never store:

Password
Credit card
Secrets
Enter fullscreen mode Exit fullscreen mode

inside JWT.


Part 3: Signature

Signature proves:

"This token was created by a trusted issuer and was not modified."


Example:

Authorization Server:

Header + Payload

        |
        v

Private Key

        |
        v

Signature
Enter fullscreen mode Exit fullscreen mode

Final JWT:

Header.Payload.Signature
Enter fullscreen mode Exit fullscreen mode

5. Public Key and Private Key

JWT commonly uses asymmetric cryptography.


Private Key

Secret.

Only authorization server owns it.

Example:

Okta Private Key
Enter fullscreen mode Exit fullscreen mode

Used for:

Signing JWT
Enter fullscreen mode Exit fullscreen mode

Public Key

Can be shared.

Example:

Spring Boot API
Enter fullscreen mode Exit fullscreen mode

uses:

Okta Public Key
Enter fullscreen mode Exit fullscreen mode

to verify.

Flow:

Okta

Private Key
     |
     |
     v
Sign JWT


Spring Boot

Public Key
     |
     |
     v
Verify JWT
Enter fullscreen mode Exit fullscreen mode

6. How JWT Validation Works

Client sends:

GET /orders

Authorization:

Bearer JWT_TOKEN
Enter fullscreen mode Exit fullscreen mode

Spring Boot receives:

HEADER.PAYLOAD.SIGNATURE
Enter fullscreen mode Exit fullscreen mode

Checks:


1. Signature Validation

Spring calculates:

Verify(
 Header + Payload,
 Public Key
)
Enter fullscreen mode Exit fullscreen mode

If valid:

Token came from trusted issuer
Enter fullscreen mode Exit fullscreen mode

2. Expiration

Checks:

exp
Enter fullscreen mode Exit fullscreen mode

Example:

{
 "exp":1788888888
}
Enter fullscreen mode Exit fullscreen mode

3. Claims

Checks:

Example:

role = ADMIN
Enter fullscreen mode Exit fullscreen mode

Allows:

DELETE /users
Enter fullscreen mode Exit fullscreen mode

7. Stateless Nature of JWT

JWT is called stateless because:

Server does not store:

User Session
Enter fullscreen mode Exit fullscreen mode

Every request contains:

All required information
Enter fullscreen mode Exit fullscreen mode

Example:

Request

+
JWT

=
Enough information
Enter fullscreen mode Exit fullscreen mode

Benefits:

  • Easy horizontal scaling
  • Works well with microservices
  • No central session storage

8. JWT Security Best Practices

Short-lived Access Tokens

Example:

Access Token:

5 minutes
15 minutes
1 hour
Enter fullscreen mode Exit fullscreen mode

Why?

If stolen:

Attacker has limited time
Enter fullscreen mode Exit fullscreen mode

9. Refresh Token

Problem:

If access token expires every 15 minutes:

User must login repeatedly.

Solution:

Refresh token.


Flow:

Access Token

expires

        |
        v

Refresh Token

        |
        v

Authorization Server

        |
        v

New Access Token
Enter fullscreen mode Exit fullscreen mode

Example:

Access Token:

15 minutes
Enter fullscreen mode Exit fullscreen mode

Refresh Token:

days/weeks
Enter fullscreen mode Exit fullscreen mode

10. OAuth2 Relationship With JWT

Important:

OAuth2 does not require JWT.

OAuth2 defines:

How to get access
Enter fullscreen mode Exit fullscreen mode

JWT defines:

How to represent the token
Enter fullscreen mode Exit fullscreen mode

Together:

OAuth2
   |
   |
   v
Access Token

   |
   |
   v

JWT Format
Enter fullscreen mode Exit fullscreen mode

11. OAuth2 Components

Resource Owner

User.


Client

Application requesting access.

Example:

Angular Application
Enter fullscreen mode Exit fullscreen mode

Authorization Server

Creates tokens.

Examples:

Okta
Google
Azure AD
Auth0
Enter fullscreen mode Exit fullscreen mode

Resource Server

API protecting resources.

Example:

Spring Boot API
Enter fullscreen mode Exit fullscreen mode

12. OAuth2 Production Flow

Architecture:

Browser

Angular

Spring Boot API

Okta
Enter fullscreen mode Exit fullscreen mode

Phase 1: Backend Startup

Spring Boot starts.

Configuration:

issuer-uri=https://okta.com/oauth2/default
Enter fullscreen mode Exit fullscreen mode

Spring calls:

GET

/.well-known/openid-configuration
Enter fullscreen mode Exit fullscreen mode

This is a REST API.

Response:

{
 "authorization_endpoint":"",
 "token_endpoint":"",
 "jwks_uri":""
}
Enter fullscreen mode Exit fullscreen mode

Spring learns:

Where are public keys?
How to validate tokens?
Enter fullscreen mode Exit fullscreen mode

Phase 2: User Login

Browser opens:

https://myapp.com
Enter fullscreen mode Exit fullscreen mode

Angular loads.

Angular checks:

Do I have token?
Enter fullscreen mode Exit fullscreen mode

If no:

Redirect:

Browser

      |
      v

Okta Login Page
Enter fullscreen mode Exit fullscreen mode

Phase 3: User Authentication

User enters:

Username
Password
MFA
Enter fullscreen mode Exit fullscreen mode

Important:

Password goes to:

Okta
Enter fullscreen mode Exit fullscreen mode

Not:

Angular
Spring Boot
Enter fullscreen mode Exit fullscreen mode

Phase 4: Authorization Code

Okta returns:

authorization_code
Enter fullscreen mode Exit fullscreen mode

Example:

callback?code=abc123
Enter fullscreen mode Exit fullscreen mode

Phase 5: Token Exchange

Application calls:

POST /token
Enter fullscreen mode Exit fullscreen mode

Okta returns:

Access Token (JWT)
Refresh Token
Enter fullscreen mode Exit fullscreen mode

Phase 6: API Request

Angular sends:

GET /orders

Authorization:
Bearer JWT
Enter fullscreen mode Exit fullscreen mode

Phase 7: Spring Validation

Spring verifies:

JWT Signature

using

Okta Public Key
Enter fullscreen mode Exit fullscreen mode

If valid:

Request allowed
Enter fullscreen mode Exit fullscreen mode

13. PKCE (Proof Key for Code Exchange)

Used mainly for:

Angular
React
Mobile Apps
Enter fullscreen mode Exit fullscreen mode

because they cannot store:

client_secret
Enter fullscreen mode Exit fullscreen mode

PKCE Memory Rule

Remember:

CREATE
HIDE
PROVE
Enter fullscreen mode Exit fullscreen mode

1. Create

Angular creates:

code_verifier
Enter fullscreen mode Exit fullscreen mode

Example:

ABC123_SECRET
Enter fullscreen mode Exit fullscreen mode

2. Hide

Creates:

SHA256(code_verifier)
Enter fullscreen mode Exit fullscreen mode

Result:

code_challenge
Enter fullscreen mode Exit fullscreen mode

Sends:

code_challenge
Enter fullscreen mode Exit fullscreen mode

to Okta.

Keeps:

code_verifier
Enter fullscreen mode Exit fullscreen mode

secret.


3. Prove

Later sends:

authorization_code

+

code_verifier
Enter fullscreen mode Exit fullscreen mode

Okta checks:

SHA256(verifier)

=

stored challenge
Enter fullscreen mode Exit fullscreen mode

If match:

Issue JWT
Enter fullscreen mode Exit fullscreen mode

14. Implicit Flow (Old)

Old SPA flow:

Browser

     |
     v

Authorization Server

     |
     v

JWT Token Directly

     |
     v

Angular
Enter fullscreen mode Exit fullscreen mode

Problem:

Token exposed to browser.

Risks:

  • Browser history
  • URL leaks
  • XSS attacks

15. Token Storage Options

Local Storage

Example:

localStorage.setItem(
 "token",
 jwt
)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

JavaScript cannot access it.

More secure.

Common with:

Backend For Frontend (BFF)
Enter fullscreen mode Exit fullscreen mode

16. Modern Recommendation

For SPA applications:

Use:

Authorization Code Flow
+
PKCE
Enter fullscreen mode Exit fullscreen mode

Avoid:

Implicit Flow
Enter fullscreen mode Exit fullscreen mode

Summary

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
Enter fullscreen mode Exit fullscreen mode

Top comments (0)