Skip to content

Login

POST /auth/login
{
  "identifier": "user@example.com",
  "password": "strongpassword123",
  "totp_code": "123456"
}

totp_code is only required if the user has MFA enabled (see MFA).

Identifier resolution

identifier is matched against WardenConfig.login_identifier_fields in order — the first field type with a match wins:

WardenConfig(secret_key="...", login_identifier_fields=["username", "email"])

With the above, "identifier": "johndoe" is tried as a username first; if no username matches, it's tried as an email.

Response

{
  "access_token": "...",
  "refresh_token": "...",
  "token_type": "bearer",
  "user": { "...": "UserRead fields" }
}

200 OK on success.

Brute force protection

Every failed attempt increments failed_login_attempts on the account. After max_login_attempts consecutive failures, the account locks for login_lockout_duration seconds (AccountLocked, status 423). The counter resets to zero on the next successful login. Set max_login_attempts=0 to disable lockout entirely.

A login attempt against an unknown identifier still runs a dummy password verification before returning InvalidCredentials — this normalizes response timing so an attacker can't distinguish "wrong password" from "no such account" by response latency.

Errors

Status Exception When
401 InvalidCredentials Unknown identifier, or wrong password.
423 AccountLocked Too many recent failed attempts.
403 AccountInactive Account deactivated.
403 EmailNotVerified require_email_verification=True and the account isn't verified yet.
403 MFARequired MFA is enabled on the account but no totp_code was supplied.
401 InvalidMFACode Wrong totp_code.