# Authentication System

`aiosmtpd` provides a framework for SMTP Authentication that fully complies with RFC 4954.

## Activating Authentication

`aiosmtpd` authentication is always activated, but attempts to authenticate will always be rejected unless the `authenticator` parameter of `SMTP` is set to a valid & working Authenticator Callback.

## AUTH API

The `aiosmtpd` Authentication Framework comprises several components, who are collectivelly called the “AUTH API”.

### AUTH Handler Hook

async handle_AUTH(server: SMTP, session: Session, envelope: Envelope, args)

  Called to handle `AUTH` command, if you need custom AUTH behavior.

  Most of the time, you will NOT need to implement this hook; AUTH Mechanism Hooks are provided to override/implement selective SMTP AUTH mechanisms (see below).

  If you do implement this hook:

  You MUST comply with RFC 4954.

  `args` will contain the list of words following the `AUTH` command.

  You will have to leverage the `SMTP.push()` and `SMTP.challenge_auth()` methods to interact with the clients.

  You will need to modify the `session.auth_data` and `session.authenticated` attributes.

  You may ignore the `envelope`.

### AUTH Mechanism Hooks

Separately from AUTH Handler Hook, `aiosmtpd` also implement support for “AUTH Mechanism Hooks”. These async hooks will implement the logic for SMTP Authentication Mechanisms.

Every AUTH Mechanism Hook is named `auth_MECHANISM` where `MECHANISM` is the all-uppercase name of the mechanism that the hook will implement.

(Mechanism is the word following the `AUTH` command sent by client.)

Important

If `MECHANISM` has a dash within its name, use double-underscore to represent the dash. For example, to implement a `MECH-WITH-DASHES` mechanism, name the AUTH hook as `auth_MECH__WITH__DASHES`.

Single underscores will not be modified. So a hook named `auth_MECH_WITH_UNDERSCORE` will implement the `MECH_WITH_UNDERSCORE` mechanism.

(If in the future a SASL mechanism with double underscores in its name gets defined, this name-mangling mechanism will be revisited. That is very unlikely to happen, though.)

Alternatively, you can also use the `auth_mechanism()` decorator, which you can import from the `aiosmtpd.smtp` module.

The SMTP class provides built-in AUTH hooks for the `LOGIN` and `PLAIN` mechanisms, named `auth_LOGIN` and `auth_PLAIN`, respectively. If the handler class implements `auth_LOGIN` and/or `auth_PLAIN`, then the methods of the handler instance will override the built-in methods.

async auth_MECHANISM(server: SMTP, args: List[str]) → aiosmtpd.smtp.AuthResult
  Parameters:

    - server – The instance of the `SMTP` class invoking the AUTH Mechanism hook

    - args – A list of string split from the characters following the `AUTH` command. `args[0]` is usually equal to `MECHANISM` (unless the `auth_mechanism()` decorator has been used).

  The AUTH hook MUST perform the actual validation of AUTH credentials.

  In the built-in AUTH hooks, this is done by invoking the function specified by the `authenticator` initialization argument.

  AUTH Mechanism Hooks in handlers are NOT required to do the same, and MAY implement their own authenticator system.

  The AUTH Mechanism Hook MUST return an instance of `AuthResult` containing the result of the Authentication process.

Important

Defining additional AUTH hooks in your handler will NOT disable the built-in LOGIN and PLAIN hooks; if you do not want to offer the LOGIN and PLAIN mechanisms, specify them in the `auth_exclude_mechanism` parameter of the `SMTP` class.

### Authenticator Callback

Authenticator(server, session, envelope, mechanism, auth_data) → AuthResult
  Parameters:

    - server – The `SMTP` instance that invoked the authenticator

    - session – A `Session` instance containing session data so far

    - envelope – An `Envelope` instance containing transaction data so far

    - mechanism (str) – name of the AUTH Mechanism chosen by the client

    - auth_data – A data structure containing authentication data gathered by the AUTH Mechanism

  Returns:

    Result of authentication

  Return type:

    AuthResult

  This function would be invoked during or at the end of an Authentication Process by AUTH Mechanisms. Based on `mechanism` and `auth_data`, this function should return a decision on whether Authentication has been successful or not.

  This function SHOULD NOT modify the attributes of `session` and `envelope`.

  The type and contents of the `auth_data` parameter is wholly at the discretion of the calling AUTH Mechanism. For the built-in `LOGIN` and `PLAIN` Mechanisms, the type of data will be `aiosmtpd.smtp.LoginPassword`

  New in version 1.3.

### AuthResult API

class AuthResult(*, success, handled, message, auth_data)
  success: bool

    This attribute indicates whether Authentication is successful or not.

  handled: bool = True

    This attribute indicates whether Authenticator Decision process (e.g., sending of status codes) have been carried out by Authenticator or not.

    If set to `True`, `smtp_AUTH()` will not perform additional processing and will simply exits.

    Applicable only if `success=False`

  message: str | None = None

    The message to send back to client, regardless of success status.

    This message will be sent as-is; as such, it MUST be prefixed with the correct SMTP Status Code and optionally, SMTP Extended Status Code.

    If not given (set/kept to `None`), `smtp_AUTH()` will use standard SMTP Status Code & Message.

  auth_data: Any = None

    Optional free-form authentication data. This will be saved by `smtp_AUTH()` into the `session.auth_data` attribute.

    If `auth_data` has the attribute `login`, then `smtp_AUTH()` will save `auth_data.login` into `session.login_data` as well. This is to cater for possible backward-compatibility requirements, where legacy handlers might be looking for `session.login_data` for some reasons.

## Security Considerations

We have taken steps to prevent leakage of sensitive information (i.e., password) through logging by overriding the `__repr__` and `__str__` methods of the `AuthResult` and `LoginPassword` classes.

However, we have no control on the (logging) output of your custom hooks. Please be very careful emitting/recording AUTH information to prevent leakage.

## Example

An example is provided in `examples/authenticated_relayer`.