Skip to content

hardwaylabs/learn-oauth-python

Repository files navigation

Python OAuth 2.1 Learning Implementation

🐍 A comprehensive Python implementation of OAuth 2.1 for educational purposes

This project provides a complete, working OAuth 2.1 implementation in Python using FastAPI, designed to help developers understand OAuth concepts through hands-on exploration. It mirrors the educational approach of the Go OAuth learning project while leveraging Python's ecosystem and modern web frameworks.

🎯 What You'll Learn

  • OAuth 2.1 Authorization Code Flow with step-by-step visualization
  • PKCE (Proof Key for Code Exchange) implementation and security benefits
  • Three-component OAuth architecture (Client, Authorization Server, Resource Server)
  • Python web development with FastAPI, Pydantic, and modern async patterns
  • Security best practices including bcrypt password hashing and token validation
  • Real-world OAuth integration patterns applicable to production systems

πŸ—οΈ Architecture Overview

The system consists of three independent FastAPI applications that communicate via HTTP:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Client App    β”‚    β”‚ Authorization Server β”‚    β”‚  Resource Server    β”‚
β”‚   Port 8080     │◄──►│     Port 8081        β”‚    β”‚     Port 8082       β”‚
β”‚                 β”‚    β”‚                      β”‚    β”‚                     β”‚
β”‚ β€’ OAuth Flow    β”‚    β”‚ β€’ User Authenticationβ”‚    β”‚ β€’ Protected Resourceβ”‚
β”‚ β€’ PKCE Gen      β”‚    β”‚ β€’ Authorization Codesβ”‚    β”‚ β€’ Token Validation  β”‚
β”‚ β€’ Token Storage β”‚    β”‚ β€’ Access Tokens      β”‚    β”‚ β€’ User Info API     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Component Responsibilities

πŸ–₯️ Client Application (Port 8080)

  • Initiates OAuth flow with PKCE challenge generation
  • Handles authorization callbacks and token exchange
  • Accesses protected resources with Bearer tokens
  • Provides educational UI showing each OAuth step

πŸ” Authorization Server (Port 8081)

  • Validates authorization requests and PKCE challenges
  • Authenticates users with demo accounts
  • Issues authorization codes with 10-minute expiration
  • Exchanges codes for access tokens after PKCE verification

πŸ›‘οΈ Resource Server (Port 8082)

  • Validates Bearer tokens from Authorization headers
  • Serves protected resources and user information
  • Demonstrates proper token-based access control
  • Provides detailed logging of resource access attempts

πŸš€ Quick Start

Prerequisites

  • Python 3.8+ (Check with python --version)
  • uv package manager (recommended) or pip

Installation

Option 1: Using uv (Recommended)

# Install uv if not already installed
curl -LsSf https://astral.sh/uv/install.sh | sh

# Clone and setup project
git clone <repository-url>
cd python-oauth-learning

# Install dependencies
uv sync

# Activate virtual environment
source .venv/bin/activate  # On macOS/Linux
# or
.venv\Scripts\activate     # On Windows

Option 2: Using pip

# Clone project
git clone <repository-url>
cd python-oauth-learning

# Create virtual environment
python -m venv venv
source venv/bin/activate   # On macOS/Linux
# or
venv\Scripts\activate      # On Windows

# Install dependencies
pip install -r requirements.txt
pip install -r requirements-dev.txt

Running the System

Start All Servers (Recommended)

# Start all three servers with health checks and monitoring
python scripts/start_all.py

This script will:

  • βœ… Check that all ports are available
  • πŸš€ Start servers in the correct order with health checks
  • πŸ“Š Display real-time status and connection information
  • πŸ”„ Monitor processes and restart if needed
  • πŸ›‘ Handle graceful shutdown with Ctrl+C

Manual Server Startup

If you prefer to start servers individually:

# Terminal 1: Authorization Server
uvicorn src.auth_server.main:app --host 0.0.0.0 --port 8081 --reload

# Terminal 2: Resource Server
uvicorn src.resource_server.main:app --host 0.0.0.0 --port 8082 --reload

# Terminal 3: Client Application
uvicorn src.client.main:app --host 0.0.0.0 --port 8080 --reload

Access the Demo

Once all servers are running:

  1. 🌐 Open your browser to http://localhost:8080
  2. πŸ”‘ Click "Start OAuth Flow" to begin the authorization process
  3. πŸ‘€ Login with demo account:
    • Username: alice, Password: password123
    • Username: bob, Password: secret456
    • Username: carol, Password: mypass789
  4. πŸ“‹ Follow the step-by-step flow and observe the detailed console logging
  5. πŸ”’ Access protected resources to complete the demonstration

πŸ“š Step-by-Step OAuth Flow Walkthrough

Step 1: Authorization Request with PKCE

The client generates a PKCE challenge and redirects to the authorization server:

# Generate PKCE challenge pair
verifier, challenge = PKCEGenerator.generate_challenge()

# Build authorization URL
auth_params = {
    'client_id': 'demo-client',
    'redirect_uri': 'http://localhost:8080/callback',
    'scope': 'read',
    'state': 'demo-state-123',
    'code_challenge': challenge,
    'code_challenge_method': 'S256',
    'response_type': 'code'
}

πŸ” What happens:

  • Client generates cryptographically secure PKCE verifier (43 characters)
  • SHA256 hash of verifier becomes the challenge
  • User is redirected to authorization server with challenge
  • State parameter prevents CSRF attacks

Step 2: User Authentication

The authorization server presents a login form:

# Demo accounts with bcrypt-hashed passwords
demo_accounts = {
    'alice': '$2b$12$...',  # password123
    'bob': '$2b$12$...',    # secret456
    'carol': '$2b$12$...'   # mypass789
}

# Verify credentials
if verify_password(password, user['password_hash']):
    # Generate authorization code
    auth_code = generate_secure_token()

πŸ” What happens:

  • User enters credentials on authorization server
  • Server validates against bcrypt-hashed passwords
  • Authorization code generated with 10-minute expiration
  • Code tied to client_id, user, and PKCE challenge

Step 3: Authorization Code Exchange

The client exchanges the code + PKCE verifier for an access token:

# Token request with PKCE verification
token_request = {
    'grant_type': 'authorization_code',
    'code': authorization_code,
    'redirect_uri': 'http://localhost:8080/callback',
    'client_id': 'demo-client',
    'code_verifier': pkce_verifier
}

# Server verifies PKCE
if PKCEGenerator.verify_challenge(verifier, stored_challenge):
    access_token = generate_secure_token()

πŸ” What happens:

  • Client sends authorization code + PKCE verifier
  • Server verifies PKCE challenge matches verifier
  • Access token issued only if PKCE verification succeeds
  • Authorization code marked as used (one-time only)

Step 4: Protected Resource Access

The client uses the Bearer token to access protected resources:

# Access protected resource
headers = {'Authorization': f'Bearer {access_token}'}
response = httpx.get('http://localhost:8082/protected', headers=headers)

# Resource server validates token
def validate_bearer_token(authorization: str = Header(None)):
    if not authorization or not authorization.startswith('Bearer '):
        raise HTTPException(401, "Invalid Authorization header")
    return authorization[7:]  # Extract token

πŸ” What happens:

  • Client includes Bearer token in Authorization header
  • Resource server validates token format and presence
  • Protected content served if token is valid
  • All requests logged with security details

πŸ”§ Demo Automation

Automated Flow Testing

Run the complete OAuth flow programmatically:

# Test single account
python scripts/demo_flow.py --username alice

# Test all demo accounts
python scripts/demo_flow.py --test-all

# Save results to file
python scripts/demo_flow.py --test-all --output results.json

# Custom server URLs
python scripts/demo_flow.py --auth-url http://localhost:9081

Password Hash Generation

Generate bcrypt hashes for new demo accounts:

# Generate hashes for all demo accounts
python scripts/hash_passwords.py

# Generate hash for specific password
python scripts/hash_passwords.py --password "newpassword123"

πŸ› οΈ Development and Customization

Project Structure

python-oauth-learning/
β”œβ”€β”€ πŸ“„ pyproject.toml              # uv project configuration
β”œβ”€β”€ πŸ“„ requirements.txt            # Production dependencies
β”œβ”€β”€ πŸ“„ requirements-dev.txt        # Development dependencies
β”œβ”€β”€ πŸ“ src/
β”‚   β”œβ”€β”€ πŸ“ shared/                 # Common utilities and models
β”‚   β”‚   β”œβ”€β”€ 🐍 oauth_models.py     # Pydantic models for validation
β”‚   β”‚   β”œβ”€β”€ πŸ” crypto_utils.py     # PKCE and token generation
β”‚   β”‚   β”œβ”€β”€ πŸ“Š logging_utils.py    # Colored console logging
β”‚   β”‚   └── πŸ›‘οΈ security.py         # Password hashing utilities
β”‚   β”œβ”€β”€ πŸ“ client/                 # Client application (Port 8080)
β”‚   β”‚   β”œβ”€β”€ 🐍 main.py             # FastAPI app and configuration
β”‚   β”‚   β”œβ”€β”€ πŸ›£οΈ routes.py           # OAuth flow endpoints
β”‚   β”‚   β”œβ”€β”€ πŸ“ templates/          # Jinja2 HTML templates
β”‚   β”‚   └── πŸ“ static/             # CSS and JavaScript files
β”‚   β”œβ”€β”€ πŸ“ auth_server/           # Authorization server (Port 8081)
β”‚   β”‚   β”œβ”€β”€ 🐍 main.py             # FastAPI app and configuration
β”‚   β”‚   β”œβ”€β”€ πŸ›£οΈ routes.py           # OAuth authorization endpoints
β”‚   β”‚   β”œβ”€β”€ πŸ’Ύ storage.py          # In-memory user and code storage
β”‚   β”‚   └── πŸ“ templates/          # Login form templates
β”‚   └── πŸ“ resource_server/       # Resource server (Port 8082)
β”‚       β”œβ”€β”€ 🐍 main.py             # FastAPI app and configuration
β”‚       β”œβ”€β”€ πŸ›£οΈ routes.py           # Protected resource endpoints
β”‚       β”œβ”€β”€ πŸ›‘οΈ middleware.py       # Token validation middleware
β”‚       └── πŸ“ data/               # Protected resource files
β”œβ”€β”€ πŸ“ scripts/                   # Utility and automation scripts
β”‚   β”œβ”€β”€ πŸš€ start_all.py           # Multi-server startup with monitoring
β”‚   β”œβ”€β”€ πŸ” hash_passwords.py      # Password hash generation
β”‚   └── πŸ€– demo_flow.py           # Automated OAuth flow testing
└── πŸ“ tests/                     # Test suite
    β”œβ”€β”€ πŸ§ͺ test_crypto_utils.py   # PKCE and crypto function tests
    └── πŸ§ͺ test_oauth_flow.py     # Integration tests

Key Python Libraries Used

  • FastAPI - Modern async web framework with automatic API docs
  • Pydantic - Data validation using Python type hints
  • uvicorn - ASGI server for running FastAPI applications
  • Jinja2 - Template engine for HTML rendering
  • passlib - Password hashing library with bcrypt support
  • httpx - Async HTTP client for server-to-server communication
  • colorama - Cross-platform colored terminal output

Adding New Demo Accounts

  1. Generate password hash:

    python scripts/hash_passwords.py --password "newpassword"
  2. Add to user store in src/auth_server/storage.py:

    self._users = {
        'alice': {'password_hash': '$2b$12$...', 'email': '[email protected]'},
        'newuser': {'password_hash': '$2b$12$...', 'email': '[email protected]'},
    }
  3. Update demo account list in templates and documentation

Extending OAuth Scopes

  1. Define new scopes in src/shared/oauth_models.py:

    class OAuthScope(str, Enum):
        READ = "read"
        WRITE = "write"
        ADMIN = "admin"
  2. Add scope validation in authorization server

  3. Implement scope-based access control in resource server

Custom Resource Endpoints

Add new protected endpoints in src/resource_server/routes.py:

@app.get("/api/profile")
async def get_user_profile(token: str = Depends(validate_bearer_token)):
    """Get user profile information"""
    # Implement profile logic
    return {"profile": "user_data"}

πŸ” Educational Features

Detailed Console Logging

The system provides comprehensive, color-coded logging of all OAuth messages:

[2024-01-15 10:30:15] CLIENT β†’ AUTH-SERVER
Authorization Request:
  client_id: demo-client
  redirect_uri: http://localhost:8080/callback
  scope: read
  state: demo-state-123
  code_challenge: dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
  code_challenge_method: S256
  response_type: code
--------------------------------------------------

PKCE Implementation Details

The PKCE implementation demonstrates RFC 7636 compliance:

# Code verifier: 43-character base64url string
verifier = base64.urlsafe_b64encode(secrets.token_bytes(32)).decode('utf-8').rstrip('=')

# Code challenge: SHA256 hash of verifier
challenge = base64.urlsafe_b64encode(
    hashlib.sha256(verifier.encode('utf-8')).digest()
).decode('utf-8').rstrip('=')

# Verification: constant-time comparison
def verify_challenge(verifier: str, challenge: str) -> bool:
    expected = base64.urlsafe_b64encode(
        hashlib.sha256(verifier.encode('utf-8')).digest()
    ).decode('utf-8').rstrip('=')
    return secrets.compare_digest(expected, challenge)

Security Best Practices Demonstrated

  • πŸ” PKCE mandatory - All authorization flows require PKCE
  • ⏰ Short-lived codes - Authorization codes expire in 10 minutes
  • πŸ”’ Secure token generation - Cryptographically secure random tokens
  • πŸ›‘οΈ bcrypt password hashing - Industry-standard password protection
  • 🚫 One-time code use - Authorization codes invalidated after use
  • 🎲 CSRF protection - State parameter validation
  • ⚑ Constant-time comparison - Prevents timing attacks

πŸ§ͺ Testing

Running Tests

# Run all tests
pytest

# Run with coverage
pytest --cov=src

# Run specific test file
pytest tests/test_crypto_utils.py

# Run with verbose output
pytest -v

Test Categories

Unit Tests - Test individual components:

  • PKCE generation and verification
  • Password hashing and validation
  • OAuth model validation
  • Token generation utilities

Integration Tests - Test complete flows:

  • End-to-end OAuth authorization
  • Multi-server communication
  • Error handling scenarios
  • Security validation

Manual Testing Scenarios

  1. Happy Path Flow

    • Complete OAuth flow with valid credentials
    • Verify all steps complete successfully
    • Check token-based resource access
  2. Error Scenarios

    • Invalid PKCE verifier
    • Expired authorization code
    • Missing or malformed tokens
    • Invalid user credentials
  3. Security Tests

    • CSRF attack prevention (state parameter)
    • Authorization code interception (PKCE protection)
    • Token replay attacks
    • Scope validation

🚨 Troubleshooting

Common Issues

❌ Port Already in Use

# Check what's using the port
lsof -i :8080
# Kill the process
kill -9 <PID>

❌ Module Import Errors

# Ensure you're in the project root and virtual environment is activated
pwd  # Should show python-oauth-learning directory
which python  # Should show virtual environment path

# Reinstall dependencies
pip install -r requirements.txt

❌ Server Health Check Failures

# Check server logs for startup errors
python scripts/start_all.py

# Test individual server health
curl http://localhost:8081/health
curl http://localhost:8082/health
curl http://localhost:8080/health

❌ PKCE Verification Failures

  • Ensure code verifier is stored correctly in session
  • Check that challenge generation uses SHA256
  • Verify base64url encoding (no padding)

❌ Authentication Failures

  • Verify demo account passwords match hashed values
  • Check bcrypt hash generation
  • Ensure password verification uses correct hash

Debug Mode

Enable detailed debugging:

# Set debug environment variables
export OAUTH_DEBUG=true
export LOG_LEVEL=DEBUG

# Run with debug logging
python scripts/start_all.py

Performance Issues

Slow Startup:

  • Check available system resources
  • Ensure no port conflicts
  • Verify network connectivity between servers

High Memory Usage:

  • Monitor process memory with top or htop
  • Check for memory leaks in long-running processes
  • Consider restarting servers periodically

🀝 Contributing

Development Setup

  1. Fork and clone the repository

  2. Install development dependencies:

    uv sync --dev
    # or
    pip install -r requirements-dev.txt
  3. Install pre-commit hooks:

    pre-commit install
  4. Run tests to ensure everything works:

    pytest

Code Style

The project uses:

  • Black for code formatting
  • Ruff for linting
  • Type hints throughout the codebase
  • Docstrings for all public functions and classes
# Format code
black src/ tests/ scripts/

# Lint code
ruff check src/ tests/ scripts/

# Type checking
mypy src/

Adding Features

  1. Create feature branch: git checkout -b feature/new-feature
  2. Write tests first (TDD approach)
  3. Implement feature with proper documentation
  4. Update README if needed
  5. Submit pull request with clear description

πŸ“– Additional Resources

OAuth 2.1 Specification

Python Web Development

Security Best Practices

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ™ Acknowledgments

  • Inspired by the Go OAuth learning implementation
  • Built with modern Python web development best practices
  • Designed for educational use and real-world understanding

πŸŽ“ Happy Learning! This implementation provides a solid foundation for understanding OAuth 2.1 concepts and building secure, modern web applications with Python.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published