Dev.to Security 🔐 Cybersecurity 👁 0 📖 5 min read

JWT + OAuth2 + OIDC + PKCE Complete small Guide

The flow will be: Authentication foundation Session vs JWT JWT deep dive JWT security Access/Refresh tokens OAuth2 relationship with JWT End-to-end production flow PKCE Storage strategies summary 1. Authe

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

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
   |
   v
Server

Server creates:

Session ID = abc123

Stores:

Database / Memory

abc123
 |
 |
User:
Bhargav
Role:
ADMIN

Browser receives:

Cookie:

SESSION_ID=abc123

Every Request

Browser sends:

GET /orders

Cookie:
SESSION_ID=abc123

Server:

Receive Session ID

        |
        v

Search session storage

        |
        v

Find user

        |
        v

Allow request

Problems with Sessions

1. Server maintains state

The server must remember:

Session ID
      |
      v
User Information

2. Scaling problem

Imagine multiple servers:

             Load Balancer

          /              \

     Server A          Server B

User logs in:

Server A

Session stored here

Next request:

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

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

Example:

eyJhbGciOiJIUzI1Ni...

JWT vs Session

Session

Server stores user state:

Server

Session ID
    |
    v
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 decode:

Base64 decode

Therefore never store:

Password
Credit card
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

        |
        v

Private Key

        |
        v

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.

Example:

Okta Private Key

Used for:

Signing JWT

Public Key

Can be shared.

Example:

Spring Boot API

uses:

Okta Public Key

to verify.

Flow:

Okta

Private Key
     |
     |
     v
Sign JWT


Spring Boot

Public Key
     |
     |
     v
Verify JWT

6. How JWT Validation Works

Client sends:

GET /orders

Authorization:

Bearer JWT_TOKEN

Spring Boot receives:

HEADER.PAYLOAD.SIGNATURE

Checks:

1. Signature Validation

Spring calculates:

Verify(
 Header + Payload,
 Public Key
)

If valid:

Token came from trusted issuer

2. Expiration

Checks:

exp

Example:

{
 "exp":1788888888
}

3. Claims

Checks:

Example:

role = ADMIN

Allows:

DELETE /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:

Access Token:

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 login 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.

Example:

Angular Application

Authorization Server

Creates tokens.

Examples:

Okta
Google
Azure AD
Auth0

Resource Server

API protecting resources.

Example:

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

This is 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:

Browser

      |
      v

Okta Login Page

Phase 3: User Authentication

User enters:

Username
Password
MFA

Important:

Password goes to:

Okta

Not:

Angular
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

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

1. Create

Angular creates:

code_verifier

Example:

ABC123_SECRET

2. Hide

Creates:

SHA256(code_verifier)

Result:

code_challenge

Sends:

code_challenge

to Okta.

Keeps:

code_verifier

secret.

3. 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 to 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

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
📰 Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.