b03ebab747
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
5.8 KiB
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:
- Mock Mode (Default): Uses
mock-oauth2-servervia testcontainers for fast, deterministic tests - 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
-
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
-
conftest_oauth.py: Pytest fixtures for OAuth testing
mock_oauth_server: Session-scoped mock server fixtureoauth_config: OAuth configuration (mock or real)oauth_enabled_app: Test client with OAuth enabledoauth_test_token: Generate test JWT tokenstest_user_info: Test user claims
-
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 modeUSE_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:
- Check Docker resources (CPU, memory)
- Check if port 8080 is available
- Try running with
-sflag to see container logs
Token Validation Fails
The mock server generates valid JWTs that can be verified using its JWKS endpoint. If validation fails:
- Ensure the token was created from the correct mock server instance
- Check the
aud(audience) claim matches your client ID - Verify the
iss(issuer) claim matches the mock server URL
Benefits of This Approach
- Fast: Mock server starts in <1s, tests run quickly
- Deterministic: No external dependencies, same results every time
- Realistic: Tests actual OAuth flows with real OIDC endpoints
- Flexible: Can switch to real OAuth for integration tests
- CI-Friendly: Works in ephemeral CI environments
- Complete: All OIDC endpoints available for testing