# Account Management | OAuth2 Support - Docker Mailserver
A fullstack but simple mail-server (SMTP, IMAP, LDAP, Anti-spam, Anti-virus, etc.) using Docker.
Author: docker-mailserver (Github Organization)

Skip to content

# Authentication - OAuth2 / OIDC

This feature enables support for delegating DMS account authentication through to an external Identity Provider (IdP).

Receiving mail requires a DMS account to exist

If you expect DMS to receive mail, you must provision an account into DMS in advance. Otherwise DMS has no awareness of your externally manmaged users and will reject delivery.

There are plans to implement support to provision users through a SCIM 2.0 API. An IdP that can operate as a SCIM Client (eg: Authentik) would then integrate with DMS for user provisioning. Until then you must keep your user accounts in sync manually via your configured `ACCOUNT_PROVISIONER`.

How the feature works

1. A mail client must have support to acquire an OAuth2 token from your IdP (however many clients lack generic OAuth2 / OIDC provider support).
2. The mail client then provides that token as the user password via the login mechanism `XOAUTH2` or `OAUTHBEARER`.
3. DMS (Dovecot) will then check the validity of that token against the Authentication Service it was configured with.
4. If the response returned is valid for the user account, authentication is successful.

XOAUTH2 (Googles widely adopted implementation) and OAUTHBEARER (the newer variant standardized by RFC 7628 in 2015) are supported as standards for verifying that a OAuth Bearer Token (RFC 6750 from 2012) is valid at the identity provider that created the token. The token itself in both cases is expected to be can an opaque Access Token, but it is possible to use a JWT ID Token (which encodes additional information into the token itself).

A mail client like Thunderbird has limited OAuth2 / OIDC support. The software maintains a hard-coded list of providers supported. Roundcube is a webmail client that does have support for generic providers, allowing you to integrate with a broader range of IdP services.

Documentation for this feature is WIP

See the initial feature support and existing issues for guidance that has not yet been documented officially.

Verify authentication works

If you have a compatible mail client you can verify login through that.

CLI - Verify with `curl`

    # Shell into your DMS container:
    docker exec -it dms bash

    # Adjust these variables for the methods below to use:
    export AUTH_METHOD='OAUTHBEARER' USER_ACCOUNT='hello@example.com' ACCESS_TOKEN='DMS_YWNjZXNzX3Rva2Vu'

    # Authenticate via IMAP (Dovecot):
    curl --silent --url 'imap://localhost:143' \
        --login-options "AUTH=${AUTH_METHOD}" --user "${USER_ACCOUNT}" --oauth2-bearer "${ACCESS_TOKEN}" \
        --request 'LOGOUT' \
        && grep "dovecot: imap-login: Login: user=<${USER_ACCOUNT}>, method=${AUTH_METHOD}" /var/log/mail/mail.log

    # Authenticate via SMTP (Postfix), sending a mail with the same sender(from) and recipient(to) address:
    # NOTE: `curl` seems to require `--upload-file` with some mail content provided to test SMTP auth.
    curl --silent --url 'smtp://localhost:587' \
        --login-options "AUTH=${AUTH_METHOD}" --user "${USER_ACCOUNT}" --oauth2-bearer "${ACCESS_TOKEN}" \
        --mail-from "${USER_ACCOUNT}" --mail-rcpt "${USER_ACCOUNT}" --upload-file - <<< 'RFC 5322 content - not important' \
        && grep "postfix/submission/smtpd.*, sasl_method=${AUTH_METHOD}, sasl_username=${USER_ACCOUNT}" /var/log/mail/mail.log

Troubleshooting:

- Add `--verbose` to the curl options. This will output the protocol exchange which includes if authentication was successful or failed.
- The above example chains the `curl` commands with `grep` on DMS logs (for Dovecot and Postfix services). When not running `curl` from the DMS container, ensure you check the logs correctly, or inspect the `--verbose` output instead.

`curl` bug with `XOAUTH2`

Older releases of `curl` have a bug with `XOAUTH2` support since `7.80.0` (Nov 2021) but fixed from `8.6.0` (Jan 2024). It treats `XOAUTH2` as `OAUTHBEARER`.

If you use `docker exec` to run `curl` from within DMS, the current DMS v14 release (Debian 12 with curl `7.88.1`) is affected by this bug.

## Config Examples

### Authentik with Roundcube

This example assumes you have already set up:

- A working DMS server
- An Authentik server (documentation)
- A Roundcube server (docker image or bare metal install)

Setup Instructions

1. Docker Mailserver2. Authentik3. Roundcube

Update your Docker Compose ENV config to include:

compose.yaml

    services:
      mailserver:
        env:
          # Enable the feature:
          - ENABLE_OAUTH2=1
          # Specify the user info endpoint URL of the oauth2 server for token inspection:
          - OAUTH2_INTROSPECTION_URL=https://authentik.example.com/application/o/userinfo/

1. Create a new OAuth2 provider.
2. Note the client id and client secret. Roundcube will need this.
3. Set the allowed redirect url to the equivalent of `https://roundcube.example.com/index.php/login/oauth` for your RoundCube instance.

Add the following to `oauth2.inc.php` (documentation):

    $config['oauth_provider'] = 'generic';
    $config['oauth_provider_name'] = 'Authentik';
    $config['oauth_client_id'] = '<insert client id here>';
    $config['oauth_client_secret'] = '<insert client secret here>';
    $config['oauth_auth_uri'] = 'https://authentik.example.com/application/o/authorize/';
    $config['oauth_token_uri'] = 'https://authentik.example.com/application/o/token/';
    $config['oauth_identity_uri'] = 'https://authentik.example.com/application/o/userinfo/';

    // Optional: disable SSL certificate check on HTTP requests to OAuth server. For possible values, see:
    // http://docs.guzzlephp.org/en/stable/request-options.html#verify
    $config['oauth_verify_peer'] = false;

    $config['oauth_scope'] = 'email openid profile';
    $config['oauth_identity_fields'] = ['email'];

    // Boolean: automatically redirect to OAuth login when opening Roundcube without a valid session
    $config['oauth_login_redirect'] = false;