-
-
Notifications
You must be signed in to change notification settings - Fork 333
Security Profiles and Token Binding
This page describes the settings that harden the interaction between mod_auth_openidc and the
Provider beyond plain OpenID Connect Core: security profiles (OIDCProfile), Pushed Authorization
Requests, and the two ways of sender-constraining tokens - DPoP and mutual TLS.
OIDCProfile selects a coherent set of defaults rather than requiring each individual setting to be
turned on by hand. It configures:
- the Authentication Request method
- DPoP
- PKCE
- ID token
audvalues - token endpoint JWT authentication
audvalues - the
issparameter requirement in authentication responses - whether the
scopeparameter is sent alongside arequest_uriin the authentication request
# OIDC10: adheres to the core OpenID Connect spec v1.0 (the default)
# FAPI20: the FAPI 2.0 Security Profile, i.e.:
# Auth Request Method: PAR, DPoP: Required, PKCE: S256, aud: client_id,
# token endpoint JWT aud: iss, iss parameter: required,
# scope: omitted when a request_uri is used
#OIDCProfile [ OIDC10 | FAPI20 ]Individual directives still override what the profile sets, so a profile is a starting point, not a lock.
With PAR, the authentication request parameters are POSTed to the Provider over a back channel and
the browser is only sent a short request_uri reference, so the parameters cannot be inspected or
tampered with in the front channel.
# Send authentication request parameters to the Pushed Authorization Request endpoint
OIDCProviderAuthRequestMethod PAR
# Only needed when OIDCProviderMetadataURL is not used, or the discovered metadata does
# not advertise "pushed_authorization_request_endpoint"
#OIDCProviderPushedAuthorizationRequestEndpoint <url>OIDCProviderAuthRequestMethod is also settable per Provider through the auth_request_method key
in the Provider's .conf file, see Multiple Providers.
It is implied by OIDCProfile FAPI20.
A plain bearer access token can be replayed by whoever obtains it. Both mechanisms below bind the token to a key that the legitimate client holds, so a stolen token on its own is not enough.
DPoP binds the token to a key held by mod_auth_openidc, proven per request with a signed proof
JWT. It requires a signing key, so OIDCPrivateKeyFiles/OIDCPublicKeyFiles must be configured
with an RSA or EC private signing key.
# off: no DPoP token is requested from the OP
# optional: a DPoP token is requested but we continue even if the returned token is Bearer
# required: a DPoP token is requested and we fail if the returned token type is not DPoP
# When not defined "off" is used.
# The 2nd parameter optionally enables the DPoP proof API described below.
#OIDCDPoPMode [off|optional|required] [on|off]OIDCProfile FAPI20 implies required. The mode can be overridden per Provider with the
dpop_mode key in the Provider's .conf file.
Applications behind the module that need to use the DPoP-bound access token themselves cannot
simply replay it - each call needs a fresh proof signed with the module's key. Enabling the second
parameter of OIDCDPoPMode exposes an endpoint that mints one:
<redirect_uri>?dpop=<access_token>&url=<url>[&method=<method>][&nonce=<nonce>]
method defaults to GET. The response is a JSON object holding the proof to send in the DPoP
header alongside the access token:
{"DPoP":"eyJ0eXAiOiJkcG9wK2p3dCIs..."}Caveat: this endpoint hands out a proof for whatever access token is passed to it, so it would
undo the proof-of-possession property if it were reachable by the party holding the token. The
module therefore rejects any request whose client address is not the server's own local address, and
logs a warning telling you to instead expose it through a separate virtual (sub)host that requires
client certificate authentication and proxies the request. The check can be disabled by setting the
OIDC_DPOP_API_INSECURE environment variable, which - as the name says - you should not do outside
of testing.
RFC 8705 covers two related things that are configured separately: authenticating the client with a TLS certificate, and binding the access token to that certificate.
OIDCProviderTokenEndpointAuth tls_client_auth
# or, for a self-signed client certificate:
#OIDCProviderTokenEndpointAuth self_signed_tls_client_auth
# PEM-formatted client certificate and its private key
OIDCClientTokenEndpointCert <filename>
OIDCClientTokenEndpointKey <filename>
# Optional password for an encrypted private key; supports "exec:" like OIDCClientSecret
#OIDCClientTokenEndpointKeyPassword [ <passphrase> | "exec:/path/to/otherProgram arg1" ]These three settings are also available per Provider as token_endpoint_tls_client_cert,
token_endpoint_tls_client_key and token_endpoint_tls_client_key_pwd.
# off: only when one of the mutual-TLS client authentication methods is used, i.e. never
# inferred from the presence of a client certificate alone
# auto: additionally when a client certificate is configured and the Provider metadata
# advertises "tls_client_certificate_bound_access_tokens"
# on: additionally when a client certificate is configured, regardless of what the
# Provider advertises
# When not defined "auto" is used.
#OIDCCertBoundAccessTokens [off|auto|on]Two things are easy to get wrong here:
- The client must be registered with the OP for certificate-bound access tokens. The Provider advertising support says that the OP can bind, not that this client is set up for it.
- When the Provider publishes
mtls_endpoint_aliases, those aliases are used for the back-channel endpoints - except where an endpoint has been configured explicitly withOIDCProviderTokenEndpoint,OIDCProviderUserInfoEndpoint,OIDCProviderRevocationEndpointorOIDCProviderPushedAuthorizationRequestEndpoint, which always take precedence over the alias.
Per Provider, this is the cert_bound_tokens key.
Under OIDCProfile FAPI20 access tokens are sender-constrained through either mutual TLS or DPoP,
so on is implied and DPoP is not required on top of certificate binding.
-
Multiple Providers - the per-Provider
.confkeys for all of the above - OAuth 2.0 Resource Server - validating tokens on the receiving side
- The authoritative documentation for every directive is auth_openidc.conf