Skip to main content

A simple library for parsing and verifying externally issued OIDC ID tokens in fastapi.

Project description

FastAPI OIDC

Test Documentation Status Package version


Verify and decrypt 3rd party OIDC ID tokens to protect your fastapi endpoints.

Documentation: ReadTheDocs

Source code: Github

Table of Contents

Features

  • ✅ Verify JWT tokens from any OIDC-compliant provider
  • ✅ Automatic discovery of provider configuration via .well-known endpoints
  • ✅ Caching of signing keys and configuration for performance
  • ✅ Type-safe token validation with Pydantic
  • ✅ Support for custom token models with additional fields
  • ✅ FastAPI-native dependency injection
  • ✅ Python 3.10+ with modern type hints
  • ✅ Comprehensive test coverage
  • ✅ Production-ready and actively maintained

:warning: Note: For a simple roll-your-own example of checking OIDC tokens, see this issue.

Installation

pip install fastapi-oidc

Or with Poetry:

poetry add fastapi-oidc

Quick Start

Here's a minimal example to get you started:

from fastapi import Depends, FastAPI
from fastapi_oidc import IDToken, get_auth

# Configure OIDC authentication
authenticate_user = get_auth(
    client_id="your-client-id",
    base_authorization_server_uri="https://your-auth-server.com",
    issuer="your-auth-server.com",
    signature_cache_ttl=3600,
)

app = FastAPI()

@app.get("/")
def public():
    return {"message": "This endpoint is public"}

@app.get("/protected")
def protected(token: IDToken = Depends(authenticate_user)):
    return {"message": f"Hello {token.email}!"}

Supported Providers

fastapi-oidc works with any OIDC-compliant authentication provider:

  • Okta - Enterprise identity management
  • Auth0 - Authentication and authorization platform
  • Google OAuth 2.0 - Google identity services
  • Microsoft Azure AD / Entra ID - Microsoft identity platform
  • Keycloak - Open-source identity and access management
  • AWS Cognito - Amazon's user identity and data synchronization
  • Any OIDC-compliant provider - Supports OpenID Connect Discovery

See the examples directory for provider-specific configurations (coming soon).

Configuration

Required Parameters

Parameter Type Description
client_id str OAuth client ID from your provider
base_authorization_server_uri str Base URL of your auth server (e.g., https://dev-123456.okta.com)
issuer str | Iterable[str] Token issuer identifier(s) (usually matches base URI domain). Pass an iterable to accept tokens from any of several issuers
signature_cache_ttl int Cache duration for signing keys in seconds (recommended: 3600)

Optional Parameters

Parameter Type Default Description
audience str client_id Token audience claim to validate
token_type Type[IDToken] IDToken Custom token model (must inherit from IDToken)

Configuration Examples

Basic Configuration:

authenticate_user = get_auth(
    client_id="0oa1e3pv9opbyq2Gm4x7",
    base_authorization_server_uri="https://dev-126594.okta.com",
    issuer="dev-126594.okta.com",
    signature_cache_ttl=3600,
)

With Custom Audience:

authenticate_user = get_auth(
    client_id="your-client-id",
    audience="https://yourapi.url.com/api",
    base_authorization_server_uri="https://auth.example.com",
    issuer="auth.example.com",
    signature_cache_ttl=3600,
)

With Multiple Issuers:

authenticate_user = get_auth(
    client_id="your-client-id",
    base_authorization_server_uri="https://auth.example.com",
    issuer=["auth.example.com", "auth.internal.example.com"],
    signature_cache_ttl=3600,
)

Using Environment Variables (Recommended):

import os

authenticate_user = get_auth(
    client_id=os.getenv("OIDC_CLIENT_ID"),
    audience=os.getenv("OIDC_AUDIENCE"),
    base_authorization_server_uri=os.getenv("OIDC_BASE_URI"),
    issuer=os.getenv("OIDC_ISSUER"),
    signature_cache_ttl=int(os.getenv("OIDC_CACHE_TTL", "3600")),
)

Security Recommendations

  • ✅ Always use HTTPS in production
  • ✅ Store credentials in environment variables, not in code
  • ✅ Set cache TTL between 3600-7200 seconds for optimal balance
  • ✅ Validate the issuer matches your authentication server
  • ✅ Use short token expiration times (5-15 minutes recommended)
  • ✅ Implement application-level rate limiting
  • ✅ Monitor authentication logs for suspicious activity

See SECURITY.md for comprehensive security guidelines.

Usage Examples

Verify ID Tokens Issued by Third Party

This is great if you just want to use something like Okta or google to handle your auth. All you need to do is verify the token and then you can extract user ID info from it.

from fastapi import Depends
from fastapi import FastAPI

# Set up our OIDC
from fastapi_oidc import IDToken
from fastapi_oidc import get_auth

OIDC_config = {
    "client_id": "0oa1e3pv9opbyq2Gm4x7",
    # Audience can be omitted in which case the aud value defaults to client_id
    "audience": "https://yourapi.url.com/api",
    "base_authorization_server_uri": "https://dev-126594.okta.com",
    "issuer": "dev-126594.okta.com",
    "signature_cache_ttl": 3600,
}

authenticate_user: Callable = get_auth(**OIDC_config)

app = FastAPI()

@app.get("/protected")
def protected(id_token: IDToken = Depends(authenticate_user)):
    return {"Hello": "World", "user_email": id_token.email}

Using your own tokens

The IDToken class will accept any number of extra field but if you want to craft your own token class and validation that's accounted for too.

class CustomIDToken(fastapi_oidc.IDToken):
    custom_field: str
    custom_default: float = 3.14


authenticate_user: Callable = get_auth(**OIDC_config, token_type=CustomIDToken)

app = FastAPI()


@app.get("/protected")
def protected(id_token: CustomIDToken = Depends(authenticate_user)):
    return {"Hello": "World", "user_email": id_token.custom_default}

Troubleshooting

Common Issues

"Unauthorized: Signature verification failed"

Causes:

  • Incorrect client_id or issuer configuration
  • Token is expired
  • Authentication server is unreachable
  • Token signed with different key than expected

Solutions:

# Verify your configuration
print(f"Client ID: {client_id}")
print(f"Issuer: {issuer}")
print(f"Base URI: {base_authorization_server_uri}")

# Check token expiration
import jwt
decoded = jwt.decode(token, options={"verify_signature": False})
print(f"Token expires at: {decoded['exp']}")

# Verify network connectivity
import requests
response = requests.get(f"{base_authorization_server_uri}/.well-known/openid-configuration")
print(f"OIDC Discovery Status: {response.status_code}")

"Unauthorized: Invalid audience"

Cause: The token's aud claim doesn't match your configuration.

Solution:

# Set the audience parameter explicitly
authenticate_user = get_auth(
    client_id="your-client-id",
    audience="your-expected-audience",  # Must match token's 'aud' claim
    base_authorization_server_uri="https://auth.example.com",
    issuer="auth.example.com",
    signature_cache_ttl=3600,
)

# Or check what audience your token contains
import jwt
decoded = jwt.decode(token, options={"verify_signature": False})
print(f"Token audience: {decoded['aud']}")

"Connection timeout"

Causes:

  • Network connectivity issues
  • Firewall blocking outbound HTTPS
  • Incorrect base URI

Solutions:

# Test connectivity
curl https://your-auth-server.com/.well-known/openid-configuration

# Check firewall rules allow HTTPS to your auth server
# Verify the base URI is correct (no trailing slash)

"Module not found" or Import Errors

Solution:

# Ensure fastapi-oidc is installed
pip install fastapi-oidc

# Verify installation
python -c "import fastapi_oidc; print(fastapi_oidc.__version__)"

# Reinstall if needed
pip install --force-reinstall fastapi-oidc

Debugging Tips

Enable detailed logging:

import logging

logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger("fastapi_oidc")
logger.setLevel(logging.DEBUG)

Getting Help

Contributing

Contributions are welcome! We appreciate bug fixes, documentation improvements, and new features.

How to Contribute

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Run tests (poetry run pytest)
  5. Run code quality checks (poetry run pre-commit run --all-files)
  6. Commit your changes (git commit -m 'feat: add amazing feature')
  7. Push to the branch (git push origin feature/amazing-feature)
  8. Open a Pull Request

See CONTRIBUTING.md for detailed guidelines.

Development Setup

# Clone the repository
git clone https://github.com/HarryMWinters/fastapi-oidc.git
cd fastapi-oidc

# Install dependencies
poetry install

# Set up pre-commit hooks
poetry run pre-commit install

# Run tests
poetry run pytest

# Run with coverage
poetry run pytest --cov=fastapi_oidc

Security

Security is a top priority. Please report security vulnerabilities privately to harrymcwinters@gmail.com.

See SECURITY.md for:

  • Security best practices
  • Supported versions
  • Vulnerability reporting process
  • Known security considerations

License

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

Acknowledgments


Made with ❤️ by Harry M. Winters

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastapi_oidc-0.1.0.tar.gz (9.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastapi_oidc-0.1.0-py3-none-any.whl (11.0 kB view details)

Uploaded Python 3

File details

Details for the file fastapi_oidc-0.1.0.tar.gz.

File metadata

  • Download URL: fastapi_oidc-0.1.0.tar.gz
  • Upload date:
  • Size: 9.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.2.1 CPython/3.15.0a3 Darwin/25.5.0

File hashes

Hashes for fastapi_oidc-0.1.0.tar.gz
Algorithm Hash digest
SHA256 cac0682715ce9bd94af06d23627e8e0788d52d330b71f9be0bdd42fcc77fc4ff
MD5 bcb7eb3f11fb7cd09e0f98842c94e062
BLAKE2b-256 c994a0c7fcda48ef60de689d2966348b54a3ecd9ca2afeeee0e1c2a0b42b219b

See more details on using hashes here.

File details

Details for the file fastapi_oidc-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: fastapi_oidc-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 11.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.2.1 CPython/3.15.0a3 Darwin/25.5.0

File hashes

Hashes for fastapi_oidc-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f2c3f36340365cdc1802e6b2231d471e50b85e2fae073ca84759d834574d6e2f
MD5 f298f37ee3969daffc836ec4e40994e1
BLAKE2b-256 820af20b8df25fd04a2edb012fadfa4b71b0a6b6b38ff8cf4b77e2827992ab0c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page