Skip to content

Security: kjdev/nginx-oidc

docs/SECURITY.md

Security Considerations

This document describes the security considerations and recommended settings for using the nginx OIDC module in a production environment.

Enabling PKCE

Enable PKCE (Proof Key for Code Exchange) and use the S256 method.

Reason: This prevents Authorization Code Interception Attacks.

Configuration:

oidc_provider my_provider {
    # ...
    pkce on;                # Enable PKCE (default: on)
    code_challenge_method S256;    # Use S256 (default: S256)
}

Note: PKCE is enabled by default. It is automatically enabled unless explicitly disabled.

Using HTTPS

Always use HTTPS in production environments.

Reason: This prevents eavesdropping on tokens and cookies.

Configuration:

server {
    listen 443 ssl http2;
    server_name app.example.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    # Use TLS 1.2 or higher
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';

    # HTTP -> HTTPS redirect
    # (configured in a separate server block)
}

server {
    listen 80;
    server_name app.example.com;
    return 301 https://$server_name$request_uri;
}

Note: If TLS is terminated at a load balancer or reverse proxy and the connection to nginx is HTTP, use the oidc_base_url directive to set the externally accessible HTTPS URL. This ensures that the redirect URI is constructed correctly.

server {
    listen 80;
    oidc_base_url "https://app.example.com";
    # ...
}

Session Timeout

Configure an appropriate session timeout according to your security requirements.

Reason: If the session lifetime is too long, the risk of session hijacking increases.

Configuration:

oidc_session_store memory_store {
    ttl 28800;  # 8 hours (session store level)
}

oidc_provider my_provider {
    session_timeout 28800;  # 8 hours (provider level)
}

Relationship between ttl and session_timeout:

  • ttl (in oidc_session_store): The expiration time for server-side session data. Session data is deleted after this period
  • session_timeout (in oidc_provider): The lifetime of the session cookie sent to the browser (Max-Age attribute)

Typically, set ttl >= session_timeout. If ttl is shorter than session_timeout, the server-side session data will expire before the cookie, causing re-authentication even while the cookie is still valid.

Note: The default values are ttl = 3600 seconds (1 hour) and session_timeout = 28800 seconds (8 hours), which contradicts the recommended setting (ttl >= session_timeout). With the default settings, the server-side session will expire (1 hour) before the cookie lifetime (8 hours), causing users to be prompted for re-authentication. Address this by one of the following methods:

  • Set ttl to be equal to or greater than session_timeout (e.g., ttl 28800;)
  • Reduce session_timeout to be equal to or less than ttl (e.g., session_timeout 3600;)

Selection Guidelines:

  • High-security environments: 1 hour or less
  • Standard business applications: Approximately 8 hours
  • Public web applications: Adjust according to requirements

Client Secret Management

The client secret is sensitive information. Protect it appropriately.

Reason: If the client secret is leaked, an attacker can impersonate a legitimate client and obtain tokens fraudulently.

Best Practices:

  1. Restrict configuration file permissions:
chmod 600 /etc/nginx/nginx.conf
chown root:root /etc/nginx/nginx.conf
  1. Use environment variables (since nginx does not directly support this, use a configuration generation script):
# Example configuration generation script
CLIENT_SECRET="$(cat /run/secrets/oidc_client_secret)"
envsubst < nginx.conf.template > nginx.conf
  1. Exclude from version control:
# Add to .gitignore
nginx.conf
*.secret
  1. Regular rotation: Change the client secret periodically

SSL Verification

Enable SSL verification in the /_oidc_http_fetch location.

Reason: If SSL verification is disabled, tokens and session information may be intercepted through man-in-the-middle attacks.

Configuration:

location /_oidc_http_fetch {
    internal;
    auth_oidc off;

    # Always enable SSL verification
    proxy_ssl_verify on;
    proxy_ssl_verify_depth 2;
    proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
    proxy_ssl_server_name on;
    proxy_ssl_name $proxy_host;

    # ...
}

Warning: proxy_ssl_verify off poses a risk of man-in-the-middle attacks. Do not use it in production environments.

Cookie Security Settings

In production environments, use HTTPS and verify that the Secure attribute is enabled on cookies.

Reason: If cookies are not properly protected, there is a risk of session hijacking and CSRF attacks.

The module automatically sets the following security attributes:

  • HttpOnly: Prevents JavaScript from accessing the cookie (XSS protection). Always set (fixed)
  • SameSite=Lax: Mitigates CSRF attacks. Always set (fixed)
  • Secure: Only added when the connection to nginx is TLS (conditional). Cookies are set without the Secure attribute for non-TLS connections

HttpOnly and SameSite are always set automatically, so no additional configuration is needed. The Secure attribute is automatically determined based on the actual TLS connection state to the nginx process.

Note: The Secure attribute is determined by the actual TLS connection state to the nginx process. If TLS is terminated at a load balancer or reverse proxy and the connection to nginx is HTTP, the Secure attribute will not be added.

Countermeasures for reverse proxy environments:

  • Configure TLS on nginx as well: By using TLS communication between the load balancer and nginx, the Secure attribute will be added
  • Restrict to trusted networks: Limit communication between the load balancer and nginx to a VPC or private network to mitigate the risk of non-TLS communication

Cookie name configuration when using multiple providers:

When using multiple OIDC providers, set a different cookie_name for each provider. Using the same cookie name will cause session conflicts and prevent proper operation.

oidc_provider google {
    cookie_name "oidc_google_session";
    # ...
}

oidc_provider azure {
    cookie_name "oidc_azure_session";
    # ...
}

Automatic Security Protections

The following security features are automatically applied by the module, requiring no additional configuration.

  • State parameter: A random state parameter is generated and validated for each authentication request, preventing CSRF attacks
  • Nonce: A nonce bound to the ID Token is generated and validated, preventing replay attacks
  • at_hash verification: When the ID Token contains an at_hash claim, the binding with the access token is automatically verified
  • JWT signature verification: ID Token signatures are automatically verified using public keys obtained from the JWKS endpoint. See JWT_SUPPORTED_ALGORITHMS.md for details on supported algorithms

Input Validation and Hardening

The module automatically performs the following input validation to prevent malformed input and protocol abuse.

Size Limits

The following size limits are enforced to prevent DoS and buffer processing issues from oversized input.

Target Limit Notes
JWT token length 16 KiB ID Token, access token
JSON response size 1 MiB Token endpoint, UserInfo, etc.
JWKS JSON size 256 KiB Response from JWKS endpoint
JWKS key count 64 Keys beyond the limit are ignored

Algorithm Restrictions

  • HMAC algorithm rejection: HS256/HS384/HS512 are explicitly rejected. HMAC algorithms use symmetric keys, making them incompatible with public key-based verification (JWKS) and vulnerable to algorithm confusion attacks
  • Whitelist approach: Signature algorithms are restricted to a whitelist (RS256/RS384/RS512, PS256/PS384/PS512, ES256/ES384/ES512/ES256K, EdDSA)
  • alg-curve validation: For EC keys, the compatibility between the JWT header algorithm and the JWKS key curve is validated (ES256-P-256, ES384-P-384, ES512-P-521, ES256K-secp256k1)

Key Validation

  • RSA minimum key length: A minimum of 2048 bits (256 bytes) is required for RSA public keys. Shorter keys are rejected
  • RSA public exponent validation: The public exponent must be odd and >= 3
  • EC coordinate length validation: EC public key coordinate lengths are validated against the curve (P-256: 32B, P-384: 48B, P-521: 66B)
  • Encryption key exclusion: Encryption keys (use: "enc") in JWKS are automatically excluded from signature verification

Token Format Validation

  • JWE rejection: JWE tokens with a 5-segment structure are rejected (only 3-segment JWS structure is supported)
  • Empty segment rejection: Malformed JWTs with empty header or payload segments are rejected

JSON Parsing Protection

  • Duplicate key rejection: Duplicate keys in JSON responses are rejected, preventing ambiguity attacks via key duplication

Related Documents

There aren’t any published security advisories