oauth2
| Value | Named Filter |
|---|---|
| See Also |
Filter for oauth2 specific settings.
Note: This is pre-release documentation.
Please access https://doc.dovecot.org/latest/ for documentation on released versions.
oauth2) This database works with a OAuth2 (RFC 6749)provider.
You are recommended to use oauthbearer (preferred) or xoauth2authentication mechanisms with this database.
The responses from endpoints must be JSON objects.
Changed: 2.4.0: The OAuth2 mechanism no longer uses a passdb for token authentication. Password Grant still needs a oauth2 passdb.
Oauth2 overrides some of the default HTTP client and SSL settings. You can override these and any other HTTP client or SSL settings by placing them inside the oauth2 named filter.
oauth2| Value | Named Filter |
|---|---|
| See Also |
Filter for oauth2 specific settings.
oauth2_active_attribute| Default | [None] |
|---|---|
| Value | string |
Attribute name for (optional) checking whether account is disabled.
oauth2_active_value| Default | [None] |
|---|---|
| Value | string |
Expected value in active_attribute. (empty = require present, but anything
goes)
oauth2_fields| Default | [None] |
|---|---|
| Value | String List |
Key-value fields to include in successful authentication.
Authentication variables can be used. %{access_token} is the raw token.
%{token} Deprecated: 2.4.6 is the old name
of %{access_token} and logs a warning when used.
oauth2_force_introspection| Default | no |
|---|---|
| Value | boolean |
Force introspection even if tokeninfo contains wanted fields. Set this to
yes if you are using oauth2_active_attribute.
oauth2_introspection_mode| Default | [None] |
|---|---|
| Value | string |
| Allowed Values | <empty>authgetpostlocal |
| See Also |
To enable oauth2 you must choose how to do token introspection.
oauth2_introspection_url is not required if
oauth2_tokeninfo_url already provides all the necessary fields, or
if you are using local validation.
You can force introspection with oauth2_force_introspection, if you
need to it every time.
With local validation, oauth2_tokeninfo_url is also ignored.
| Value | Description |
|---|---|
auth |
GET request with Bearer authentication. |
get |
GET request with the token placed into oauth2_introspection_url via %{access_token}. |
post |
POST request with token=bearer_token as content. |
local |
Attempt to locally validate and decode JWT token. |
oauth2_introspection_url| Default | [None] |
|---|---|
| Value | string |
| Changes |
|
URL template for getting more information about the token.
With oauth2_introspection_mode get the URL must contain
%{access_token} in the path or query, i.e. after a literal / or ?
that follows the host part. With auth or post the token is sent via the
Authorization header or the POST body instead, and the URL must not contain
it.
Variables expanded into the URL are URL-escaped; the | safe filter opts
out. See Variables in oauth2 URLs.
Example:
oauth2_introspection_mode = get
oauth2_introspection_url = %{env:IDP_URL | safe}/introspect?token=%{access_token}
oauth2_issuers| Default | [None] |
|---|---|
| Value | Boolean List |
Valid issuer(s) for the token.
oauth2_local_validation| Value | Named Filter |
|---|---|
| See Also |
A dictionary for fetching validation keys.
Example:
oauth2_local_validation {
dict fs {
fs posix {
prefix = /tmp/keys/
}
}
}
oauth2_openid_configuration_url| Default | [None] |
|---|---|
| Value | URL |
URL to RFC 7628 OpenID Provider Configuration Information schema.
If the value has no path, e.g. https://id.example.com, a trailing /
is added when it is returned to clients in OAUTHBEARER and XOAUTH2 failure
responses.
oauth2_scope| Default | [None] |
|---|---|
| Value | Boolean List |
A list of valid scopes.
oauth2_send_auth_headers| Default | no |
|---|---|
| Value | boolean |
Whether to send special headers about authentication to remote server. If you enable this, the following headers will be sent:
X-Dovecot-Auth-ProtocolX-Dovecot-Auth-LocalX-Dovecot-Auth-Remoteoauth2_token_expire_grace| Default | 1min |
|---|---|
| Value | time |
Specifies how long after token expiration it is still accepted. It shouldn't be 0 because clocks aren't exact, and network can add some delays.
oauth2_tokeninfo_url| Default | [None] |
|---|---|
| Value | string |
| Changes |
|
URL template for verifying token validity.
The URL must contain %{access_token} in the path or query, i.e. after a
literal / or ? that follows the host part. It is replaced with the
token.
Variables expanded into the URL are URL-escaped; the | safe filter opts
out. See Variables in oauth2 URLs.
Examples:
oauth2_tokeninfo_url = http://endpoint/oauth/tokeninfo?access_token=%{access_token}
oauth2_tokeninfo_url = %{env:IDP_URL | safe}/tokeninfo?access_token=%{access_token}
oauth2_tokeninfo_url = http://idp.example.com:%{env:IDP_PORT | safe}/tokeninfo?access_token=%{access_token}
oauth2_use_worker_with_mech| Default | no |
|---|---|
| Value | boolean |
| See Also |
Use worker process to verify token. This setting only applies to mechanism. If
you want to use worker with passdb oauth2, use
passdb_use_worker instead. Worker processes are mostly useful for
distributing local token validation to multiple CPUs.
oauth2_username_attribute| Default | email |
|---|---|
| Value | string |
Username attribute in response.
oauth2_username_validation_format| Default | %{user} |
|---|---|
| Value | string |
| See Also |
Normalization for oauth2 provided username, this setting is normally not
needed. You only need this if the username that comes from authentication will
not otherwise match with oauth2_username_attribute value.
auth_mechanisms {
oauthbearer = yes
xoauth2 = yes
}
oauth2 {
# ...
}Configuration file example for Google:
oauth2 {
tokeninfo_url = https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=%{access_token}
introspection_url = https://www.googleapis.com/oauth2/v2/userinfo
#force_introspection = yes
username_attribute = email
}Configuration file example for WSO2 Identity Server:
oauth2 {
introspection_mode = post
introspection_url = https://client_id:client_secret@server.name:port/oauth2/introspect
username_attribute = username
active_attribute = active
active_value = true
}Configuration file example for Microsoft Identity Platform:
oauth2 {
introspection_mode = auth
introspection_url = https://graph.microsoft.com/v1.0/me
# this can vary on your settings
username_attribute = mail
ssl_client_ca_file = /etc/ssl/certs/ca-certificates.crt
}oauth2_tokeninfo_url and oauth2_introspection_url (with introspection_mode = get) are Settings Variables templates that must contain %{access_token} in the URL path or query. The token is not appended automatically. With introspection_mode = auth or post the introspection URL must not contain it. Other variables are limited to the builtin providers, e.g. %{env:..}. Without other variables the URL is validated when the configuration is read, otherwise after expansion.
Every variable expanded into these URLs is URL-escaped: everything except the unreserved characters of RFC 3986 is percent-encoded. A variable that provides the scheme, host, port, base URL or several path segments must use the | safe filter. Without it a variable in the scheme, host or port is rejected when the configuration is read, and / in a path variable is escaped. Variables in the userinfo are escaped and need no | safe. | safe also skips the check that rejects an escaped variable expanding to . or ... %{access_token} itself is escaped as well, so do not use | safe with it. Use | safe only for values from trusted sources.
For example, with the base URL in an environment variable:
oauth2 {
tokeninfo_url = %{env:IDP_URL | safe}/tokeninfo?access_token=%{access_token}
introspection_mode = get
introspection_url = http://idp.example.com:%{env:IDP_PORT | safe}/introspect?token=%{access_token}
}These do not work:
%{env:IDP_URL}/tokeninfo?...: rejected when the configuration is read (%{env:IDP_URL} is part of the URL scheme or host and needs the safe filter).%{env:TOKENINFO_URL}%{access_token}: the token is not in the path or query. Write %{env:TOKENINFO_BASE | safe}?access_token=%{access_token}.http://%{access_token}.example.com/: rejected with %{access_token} must be in the URL path or query.%{env:..} is resolved in the auth process, which only sees the variables listed in import_environment.
The oauth2 passdb sets the following extra fields, available as %{passdb:<name>}:
| Field | Description |
|---|---|
access_token | The raw OAuth2 bearer token. Added: 2.4.6 |
token | Deprecated: 2.4.6 Alias of access_token. |
If you want to forward oauth2 authentication to your backend, you can use various ways.
Without proxy authentication:
passdb static {
fields {
nopassword = yes
proxy = yes
proxy_mech = %{mechanism}
# ...
}
}With proxy authentication, put into dovecot.conf:
oauth2 {
# ...
fields {
proxy = y
proxy_mech = %{mech}
}
}If you want to configure proxy to get token and pass it to backend:
oauth2 {
client_id = verySecretClientId
client_secret = verySecretSecret
tokeninfo_url = http://localhost:8000/oauth2?oauth=%{access_token}
introspection_url = http://localhost:8000/introspect
introspection_mode = post
username_attribute = username
fields {
pass = %{access_token}
}
}
passdb oauth2 {
mechanisms_filter = plain login
oauth2 {
# inherit common oauth2 settings from the global scope
grant_url = http://localhost:8000/token
fields {
host = 127.0.0.1
proxy = y
proxy_mech = xoauth2
pass = %{oauth2:access_token}
}
}
}Local validation allows validating tokens without connecting to an oauth2 server.
This requires that key issuer supports JWT tokens (RFC 7519).
You can put the validation keys into any dictionary.
The lookup key used is /shared/<azp:default>/<alg>/<keyid:default>.
If there is no azp element in token body, then default is used.
The alg field is always uppercased by Dovecot.
If there is no kid element in token header, default is used.
Keys are cached into memory when they are fetched; to evict them from cache you need to restart Dovecot.
If you want to do key rotation, it is recommended to use a new key id.
Example:
{
"kid":"Zm9vb2Jhcgo",
"alg":"ES256",
"typ":"JWT"
}.{
"sub":"testuser@example.org",
"azp":"issuer.net-dovecot"
}Would turn into: /shared/issuer.net-dovecot/ES256/Zm9vb2Jhcgo.
If using fs posix, key would be at /etc/dovecot/keys/issuer.net-dovecot/ES256/Zm9vb2Jhcgo.
In key id and AZP field, / are escaped with %2f and % are escaped with %25 with any driver. This is because / is a dict key component delimiter.
When using dict-fs driver, if the path starts with ., it will be escaped using two more dots. So any . turns into ..., and any .. turns into .....
For example:
{
"kid":""./../../../../etc,
"alg":"ES256",
"typ":"JWT"
}.{
"sub":"testuser@example.org",
"azp":"attack"
}Would turn into: /etc/dovecot/keys/attack/ES256/...%2f....%2f....%2f....%2f....%2fetc%2fpasswd.
Local validation can be enabled with other oauth2 options, so that if key validation fails for non-JWT keys, then online validation is performed.
You can use local validation with password grants too. This will save you introspection roundtrip to oauth2 server.
To use local validation, put into dovecot.conf:
oauth2 {
introspection_mode = local
oauth2_local_validation {
dict fs {
fs posix {
prefix=/etc/dovecot/keys/
}
}
}
}Currently, Dovecot oauth2 library implements the following features of JWT tokens:
The following algorithms are supported
There is currently no support for EdDSA algorithms.
ES supports any curve supported by OpenSSL for this purpose.
Support for RFC 7628 OpenID Discovery (OIDC) can be achieved with openid_configuration_url. Setting this causes Dovecot to report OIDC configuration URL as openid-configuration element in error JSON.