Api Key Exposure in Django with Openid Connect
Api Key Exposure in Django with Openid Connect — how this specific combination creates or exposes the vulnerability
Api key exposure occurs when a secret key or token is unintentionally accessible to unauthorized parties. In Django, combining an OpenID Connect (OIDC) integration with how secrets are stored or logged can create scenarios where an API key or session credential is exposed. This typically happens when configuration values derived from OIDC discovery or tokens are placed into settings that are later exposed through error messages, logs, or insecure serialization.
OIDC introduces metadata such as issuer URLs, client secrets, and redirect URIs. If these values are stored in settings.py using hardcoded strings or loaded from environment variables that are accidentally printed (for example, during startup logging or debugging), an attacker who gains access to logs or error pages can recover sensitive credentials. In Django, the session framework may also store tokens or user identifiers in cookies; if the session cookie is not marked as HttpOnly, Secure, and SameSite, an OIDC access token could be leaked through cross-site scripting or client-side inspection.
Another exposure path is through introspection or token validation endpoints. When Django uses an OIDC provider's JWKS or introspection URL, misconfigured HTTP clients or verbose logging of full requests and responses can cause keys or tokens to be written to application logs. If log aggregation systems are not properly restricted, these entries become a searchable source of leaked credentials. Additionally, if the Django app exposes administrative views or debugging pages that include configuration details, an authenticated user with limited privileges might be able to view OIDC client secrets or API keys that should remain restricted to backend services.
Improper handling of redirect URIs in OIDC flows can also contribute to exposure. If the allowed redirect URIs are too permissive or not strictly validated, an attacker may capture authorization codes or tokens by redirecting the authentication flow to a malicious endpoint. Once captured, these tokens can be used to impersonate users or access downstream APIs that rely on the exposed key material. Insecure deserialization of OIDC state parameters or ID tokens can further allow an attacker to tamper with session identifiers, effectively exposing the logical key used to authenticate API calls within the application.
To detect such exposures, scanners examine whether OIDC-related configuration values appear in logs, whether session cookies lack security flags, and whether introspection or discovery endpoints leak sensitive data in error responses. Because these checks require runtime context, scanning against a live Django endpoint configured with OpenID Connect can reveal whether API keys or secrets are inadvertently surfaced through debug pages, incorrect logging, or weak transport protections.
Openid Connect-Specific Remediation in Django — concrete code fixes
Secure OIDC integration in Django starts with careful handling of secrets and tokens. Store client secrets and issuer URLs outside of version-controlled settings files and load them via environment variables using os.getenv. Never log configuration values or full HTTP requests that may contain tokens. Ensure all OIDC communication occurs over TLS and that session cookies are hardened with security flags.
import os
from django.conf import settings
# Example secure loading of OIDC configuration
OIDC_ISSUER = os.getenv('OIDC_ISSUER')
OIDC_CLIENT_ID = os.getenv('OIDC_CLIENT_ID')
OIDC_CLIENT_SECRET = os.getenv('OIDC_CLIENT_SECRET')
if not all([OIDC_ISSUER, OIDC_CLIENT_ID, OIDC_CLIENT_SECRET]):
raise RuntimeError('Missing required OIDC environment variables')
# Ensure HTTPS is enforced in production
if settings.DEBUG:
OIDC_REDIRECT_URI = 'http://localhost:8000/complete/oidc/'
else:
OIDC_REDIRECT_URI = 'https://yourdomain.com/complete/oidc/'
Configure the session to use secure cookies and restrict scope to prevent leakage through client-side scripts. Use the SESSION_COOKIE_SECURE and SESSION_COOKIE_HTTPONLY settings, and set CSRF_COOKIE_SECURE to protect cross-site request forgery tokens as well.
# settings.py additions for secure session handling
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = 'Lax'
CSRF_COOKIE_SECURE = True
CSRF_COOKIE_HTTPONLY = False # Required for forms, but ensure SameSite is set
CSRF_COOKIE_SAMESITE = 'Lax'
When using an OIDC library such as django-oauth-toolkit or mozilla-django-oidc, validate redirect URIs strictly and avoid wildcards. Here is an example of how to define a secure OIDC consumer configuration that avoids overly permissive redirect patterns.
# OIDC configuration with strict redirect validation
OIDC_RP_CLIENT_ID = os.getenv('OIDC_CLIENT_ID')
OIDC_RP_CLIENT_SECRET = os.getenv('OIDC_CLIENT_SECRET')
OIDC_OP_AUTHORIZATION_ENDPOINT = f'{OIDC_ISSUER}/protocol/openid-connect/auth'
OIDC_OP_TOKEN_ENDPOINT = f'{OIDC_ISSUER}/protocol/openid-connect/token'
OIDC_OP_USER_ENDPOINT = f'{OIDC_ISSUER}/protocol/openid-connect/userinfo'
OIDC_RP_SCOPES = ['openid', 'profile', 'email']
OIDC_ACCEPT_UNUSED_EMAIL_CLAIMS = False
OIDC_REDIRECT_URI = OIDC_REDIRECT_URI # Pre-validated above
Implement logging filters to prevent tokens and secrets from appearing in application output. Use middleware to scrub sensitive headers and query parameters before logs are written.
import re
class SensitiveDataFilter:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# Remove or mask sensitive query parameters
if 'access_token' in request.GET:
request.META['QUERY_STRING'] = re.sub(
r'(access_token=)[^&]+', r'\1***', request.META.get('QUERY_STRING', '')
)
response = self.get_response(request)
return response
Validate ID tokens strictly by checking issuer, audience, and nonce to prevent token substitution attacks. Enforce HTTPS for all OIDC endpoints and keep your certificate verification enabled to avoid man-in-the-middle exposure of API keys carried in tokens.
Regularly rotate client secrets and revoke unused OIDC credentials. Combine these practices with continuous scanning against your endpoint to ensure that no OIDC configuration or derived API key is inadvertently surfaced through error pages, logs, or misconfigured session handling.