OAuth 2.1 Implementation
Complete implementations of the OAuth 2.1 authorization code flow with PKCE in both Go and Python, designed for educational purposes.
Overview
This project demonstrates OAuth 2.1 through three interconnected applications that communicate using standard OAuth protocols. It’s designed to provide hands-on learning about OAuth security mechanisms, message exchanges, and implementation patterns.
What You’ll Learn
- OAuth 2.1 authorization code flow with mandatory PKCE
- Three-component OAuth architecture
- Security best practices and mechanisms
- Real-world implementation patterns
- Differences between OAuth 2.0 and 2.1
Available Implementations
Go Implementation
The Go implementation provides:
- Clean HTTP server implementation
- Session management with cookies
- Bcrypt password hashing
- Detailed console logging
- Browser-based testing interface
Python Implementation
The Python implementation features:
- FastAPI with async/await patterns
- Pydantic models for validation
- Jinja2 templates
- Automated testing scripts
- Multi-server management tools
Quick Start
Go Version
# Clone and setup
git clone https://github.com/hardwaylabs/learn-oauth-go
cd learn-oauth-go
go mod tidy
# Start all three servers (in separate terminals)
go run cmd/auth-server/main.go # Port 8081
go run cmd/resource-server/main.go # Port 8082
go run cmd/client/main.go # Port 8080
# Open browser to http://localhost:8080
Python Version
# Clone and setup
git clone https://github.com/hardwaylabs/learn-oauth-python
cd learn-oauth-python
# Install dependencies
uv sync # or pip install -r requirements.txt
# Start all servers
python scripts/start_all.py
# Open browser to http://localhost:8080
Demo Accounts
Both implementations include these test accounts:
- alice / password123
- bob / secret456
- carol / mypass789
OAuth 2.1 Flow Walkthrough
Step 1: Authorization Request
The client generates a PKCE challenge and redirects to the authorization server:
GET /authorize?
client_id=demo-client&
redirect_uri=http://localhost:8080/callback&
scope=read&
state=demo-state-123&
code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&
code_challenge_method=S256&
response_type=code
Step 2: User Authentication
User logs in at the authorization server. The server validates credentials against bcrypt-hashed passwords.
Step 3: Authorization Grant
After successful authentication, the server redirects back with an authorization code:
GET /callback?
code=abc123xyz&
state=demo-state-123
Step 4: Token Exchange
The client exchanges the code + PKCE verifier for an access token:
POST /token
grant_type=authorization_code&
code=abc123xyz&
redirect_uri=http://localhost:8080/callback&
client_id=demo-client&
code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
Step 5: Resource Access
The client uses the Bearer token to access protected resources:
GET /protected
Authorization: Bearer def456...
Key Security Features
PKCE (Proof Key for Code Exchange)
Prevents authorization code interception attacks:
- Client generates random 43-character verifier
- Client sends SHA256 hash as challenge
- Client proves possession of verifier during token exchange
- Server only issues token if PKCE verification succeeds
Additional Security
- State parameter: CSRF protection
- Code expiration: 10-minute lifetime
- One-time use: Codes invalidated after exchange
- Bcrypt hashing: Secure password storage
OAuth 2.1 vs OAuth 2.0
Key improvements in OAuth 2.1:
Feature | OAuth 2.0 | OAuth 2.1 |
---|---|---|
PKCE | Optional for public clients | Mandatory for all clients |
Implicit flow | Supported | Removed (security risk) |
Password grant | Supported | Removed (security risk) |
Security defaults | Various optional | Mandatory protections |
Architecture
┌─────────────────┐ ┌──────────────────────┐ ┌─────────────────┐
│ Client App │ │ Authorization Server │ │ Resource Server │
│ Port 8080 │◄──►│ Port 8081 │ │ Port 8082 │
│ │ │ │ │ │
│ • PKCE Gen │ │ • User Auth │ │ • Token Valid │
│ • Token Storage │ │ • Code Generation │ │ • Protected Res │
│ • Resource Req │ │ • Token Issuance │ │ • User Info API │
└─────────────────┘ └──────────────────────┘ └─────────────────┘
Advanced Features
Dynamic Client Registration
Both implementations support RFC 7591 dynamic client registration:
curl -X POST http://localhost:8081/register \
-H "Content-Type: application/json" \
-d '{
"redirect_uris": ["http://localhost:3000/callback"],
"client_name": "My OAuth Client"
}'
OAuth Discovery
Discovery endpoints provide automatic configuration:
curl http://localhost:8081/.well-known/oauth-authorization-server
Real-World Applications
Web Applications
- Browser-based flows with PKCE
- Session management
- Automatic token refresh
CLI Applications
- Device authorization grant (RFC 8628)
- Local callback servers
- Secure token storage
Mobile Applications
- Native app flows
- Custom URL schemes
- Biometric protection
Troubleshooting
Common Issues
“Invalid credentials”: Check password hashes match demo accounts
“PKCE verification failed”: Ensure verifier is properly stored between requests
Port conflicts: Kill existing processes or change ports in configuration
“Code not found”: Complete flow within 10-minute expiration
Extensions
After mastering the basics, try:
- Add refresh tokens with rotation
- Implement token introspection (RFC 7662)
- Add scopes and permissions
- Build client authentication
- Create a single sign-on system