---
title: "Log a user in."
method: POST
path: "/api/v1/tokens"
tags: ["Public"]
---

# Log a user in.

`POST /api/v1/tokens`

## Request

- Base URL: `https://go.outseta.com`
- URL: `https://go.outseta.com/api/v1/tokens`
- Auth: none declared

Authenticates a user and returns a JWT access token (plus a refresh token).
            
Post a JSON body with the user's credentials:
            
    { "username": "user@example.com", "password": "their-password" }
            
On success the response is `200` with an access token and refresh token:
            
    { "access_token": "eyJ...", "refresh_token": "...", "token_type": "Bearer", "expires_in": 31536000 }
            
**Two-factor authentication.** If the user has a verified 2FA method,
the password alone is not enough. After verifying the password this
endpoint instead returns `202 Accepted` with a challenge that must be
satisfied via `POST /api/v1/tokens/two-factor`:
            
    {
      "two_factor_required": true,
      "challenge_token": "eyJ...",
      "mechanism": "Totp",
      "masked_destination": "",
      "expires_in": 600,
      "available_mechanisms": ["Totp", "Email"],
      "recovery_codes_available": true
    }
            
`mechanism` is the method this challenge targets. When it is `Email`,
a one-time code has already been emailed to the user (see
`masked_destination`); when it is `Totp`, the user reads the current
code from their authenticator app and nothing is sent.
`available_mechanisms` lists every method the user has enrolled so a
client can offer a switch via `POST /api/v1/tokens/two-factor/switch-mechanism`.
            
If the tenant forces 2FA but the user has not enrolled yet, the `202`
body instead contains `"two_factor_enrollment_required": true` with a
`challenge_token` to drive the mid-login enrollment endpoints.
            
Invalid credentials return `400` with a body of `invalid_grant`.

## Query parameters

- `data` unknown, required

## Response `200`

Login succeeded; the access token (JWT) is returned.

- TokenPayload
  - `access_token` string, nullable
  - `authentication_callback_url` string, nullable
  - `expires_in` integer
  - `id_token` string, nullable
  - `refresh_token` string, nullable
  - `token_type` string, nullable

## Other responses

- `202`: A two-factor challenge (or enrollment) must be completed before a token is issued.
- `400`: Invalid credentials (`invalid_grant`) or a missing username/password.

---

[API](https://skmtc.dev/outseta/apis/outseta-api.md) · [All operations](https://skmtc.dev/outseta/apis/outseta-api/llms.txt) · [OpenAPI document](https://skmtc.dev/outseta/apis/outseta-api/revisions/c362823af82d?raw)
