Files
gh-christianlouis-docuelevate/tests/README_OAUTH_TESTING.md
2026-02-13 09:12:11 +00:00

5.8 KiB

OAuth Testing with Mock OAuth2 Server

This directory contains infrastructure for testing OAuth/OIDC authentication flows using a mock OAuth2 server.

Overview

The test setup supports two modes:

  1. Mock Mode (Default): Uses mock-oauth2-server via testcontainers for fast, deterministic tests
  2. Real Mode: Uses actual OAuth credentials from GitHub Actions secrets for integration testing

Quick Start

Running Tests with Mock OAuth

# Run all OAuth integration tests (uses mock by default)
pytest tests/test_oauth_integration_flows.py -v

# Run with coverage
pytest tests/test_oauth_integration_flows.py --cov=app.auth --cov-report=term-missing

Running Tests with Real OAuth (CI/GitHub Actions)

When running in GitHub Actions with secrets configured:

# Tests automatically detect real credentials and use them
pytest tests/test_oauth_integration_flows.py -v -m requires_external

# Force mock mode even with real credentials available
USE_MOCK_OAUTH=true pytest tests/test_oauth_integration_flows.py -v

# Force real mode (will skip if credentials not available)
USE_REAL_OAUTH=true pytest tests/test_oauth_integration_flows.py -v

Architecture

Components

  1. mock_oauth_server.py: Testcontainers wrapper for mock-oauth2-server

    • Provides complete OIDC endpoints (.well-known, token, userinfo, JWKS)
    • Generates valid JWTs for testing
    • Fast startup (<1s), no persistence needed
  2. conftest_oauth.py: Pytest fixtures for OAuth testing

    • mock_oauth_server: Session-scoped mock server fixture
    • oauth_config: OAuth configuration (mock or real)
    • oauth_enabled_app: Test client with OAuth enabled
    • oauth_test_token: Generate test JWT tokens
    • test_user_info: Test user claims
  3. test_oauth_integration_flows.py: Integration tests

    • OAuth login flow
    • Token exchange and callback
    • Session management
    • Error handling
    • Real OAuth provider tests (when credentials available)

Mock OAuth Server

The mock server (https://github.com/navikt/mock-oauth2-server) provides:

  • Authorization endpoint: /default/authorize
  • Token endpoint: /default/token
  • Userinfo endpoint: /default/userinfo
  • JWKS endpoint: /default/jwks
  • Discovery: /default/.well-known/openid-configuration
  • Debug token creation: /debugger/token

Usage Examples

Basic OAuth Test

import pytest

@pytest.mark.integration
def test_oauth_login(oauth_enabled_app):
    """Test OAuth login redirects to provider."""
    response = oauth_enabled_app.get("/oauth-login", follow_redirects=False)
    assert response.status_code == 302
    assert "authorize" in response.headers["location"]

Testing with Mock User

from unittest.mock import patch

@pytest.mark.integration
@patch("app.auth.oauth.authentik.authorize_access_token")
async def test_oauth_callback(mock_authorize, oauth_enabled_app, test_user_info):
    """Test OAuth callback with test user."""
    mock_authorize.return_value = {
        "access_token": "test-token",
        "userinfo": test_user_info,
    }

    response = oauth_enabled_app.get("/oauth-callback?code=test-code")
    assert response.status_code == 302  # Redirects after login

Testing with Generated Token

@pytest.mark.integration
def test_with_jwt_token(oauth_test_token, test_user_info):
    """Test with a valid JWT from mock server."""
    # oauth_test_token is a valid JWT signed by the mock server
    # It can be verified using the mock server's JWKS endpoint
    assert oauth_test_token is not None
    print(f"Token for user: {test_user_info['email']}")

Configuration

Environment Variables

  • USE_MOCK_OAUTH=true: Force mock mode
  • USE_REAL_OAUTH=true: Force real mode (fails if credentials not available)
  • AUTHENTIK_CLIENT_ID: OAuth client ID (for real mode)
  • AUTHENTIK_CLIENT_SECRET: OAuth client secret (for real mode)
  • AUTHENTIK_CONFIG_URL: OIDC discovery URL (for real mode)

GitHub Actions Secrets

When these secrets are set in GitHub Actions, tests automatically use real OAuth:

# .github/workflows/test.yml
env:
  AUTHENTIK_CLIENT_ID: ${{ secrets.AUTHENTIK_CLIENT_ID }}
  AUTHENTIK_CLIENT_SECRET: ${{ secrets.AUTHENTIK_CLIENT_SECRET }}
  AUTHENTIK_CONFIG_URL: ${{ secrets.AUTHENTIK_CONFIG_URL }}

Troubleshooting

Mock Server Won't Start

# Check Docker is running
docker ps

# Pull the image manually
docker pull ghcr.io/navikt/mock-oauth2-server:2.1.1

# Check logs
pytest tests/test_oauth_integration_flows.py -v -s

Tests Hang on Container Startup

The mock server fixture waits up to 30 seconds for the server to be ready. If tests hang:

  1. Check Docker resources (CPU, memory)
  2. Check if port 8080 is available
  3. Try running with -s flag to see container logs

Token Validation Fails

The mock server generates valid JWTs that can be verified using its JWKS endpoint. If validation fails:

  1. Ensure the token was created from the correct mock server instance
  2. Check the aud (audience) claim matches your client ID
  3. Verify the iss (issuer) claim matches the mock server URL

Benefits of This Approach

  1. Fast: Mock server starts in <1s, tests run quickly
  2. Deterministic: No external dependencies, same results every time
  3. Realistic: Tests actual OAuth flows with real OIDC endpoints
  4. Flexible: Can switch to real OAuth for integration tests
  5. CI-Friendly: Works in ephemeral CI environments
  6. Complete: All OIDC endpoints available for testing

Further Reading