---
title: "Authenticate a user and obtain an authorization code"
method: POST
path: "/api/auth"
tags: ["Authentication"]
---

# Authenticate a user and obtain an authorization code

`POST /api/auth`

Anonymous endpoint used by the web UI and device-flow clients to exchange
user credentials (plus optional MFA token and PKCE challenge) for an
OAuth authorization `client_code` that can then be exchanged for an
access token via `POST /auth/token`. Rate-limited as an anonymous request.

## Request body

- union — Tagged union discriminated by `type`. Use `authCode` for the standard OAuth authorization-code flow (optionally with PKCE) and `authDevice` to complete an OAuth device-authorization flow.
  - object
    - `type` 'authCode', required
    - `accountName` string, required
    - `accountSecret` string, password, required
    - `mfaToken` string, nullable — MFA token returned by a previous `mfaRequired` response
    - `clientId` string, required — OAuth client identifier
    - `redirectUri` string, uri, nullable — Must use `https://` unless the server is in recovery or dev mode
    - `nonce` string, nullable
    - `scope` string, nullable
    - `codeChallenge` string, nullable — PKCE code challenge (RFC 7636)
    - `codeChallengeMethod` 'plain' | 'S256', nullable — Defaults to `plain` when a `codeChallenge` is present
    - `state` string, nullable
  - object
    - `type` 'authDevice', required
    - `accountName` string, required
    - `accountSecret` string, password, required
    - `mfaToken` string, nullable
    - `code` string, required — User-facing device code issued by `POST /auth/device`

## Response `200`

Result of the authentication attempt

- union — Tagged union discriminated by `type`.
  - object
    - `type` 'authenticated', required
    - `clientCode` string, required — Authorization code to exchange at `POST /auth/token`
  - object
    - `type` 'verified', required
  - object
    - `type` 'mfaRequired', required
  - object
    - `type` 'failure', required

## Other responses

- `400` — Request payload is malformed or fails validation
- `429` — Anonymous-request rate limit exceeded

---

[API](https://skmtc.net/stalwartlabs/apis/stalwart-management-api.md) · [All operations](https://skmtc.net/stalwartlabs/apis/stalwart-management-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/stalwartlabs/stalwart-management-api/versions/a38a1bbfe8b2/schema)
