---
title: "Complete login with a two-factor recovery code."
method: POST
path: "/api/v1/tokens/two-factor/recovery"
tags: ["Public"]
---

# Complete login with a two-factor recovery code.

`POST /api/v1/tokens/two-factor/recovery`

## Request

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

A fallback for users who cannot produce their primary code but still
have a recovery code on file (see `recovery_codes_available` on the
login response). Post the challenge token together with one recovery
code:
            
    { "challenge_token": "eyJ...", "recovery_code": "abcd-efgh-ijkl" }
            
On success the response is `200` with the final access token, in the
same shape as `POST /api/v1/tokens`. Each recovery code is single-use.
An incorrect code returns `400` (`invalid_grant`); an expired
challenge returns `410` (`challenge_expired`). Rate limited to 10
requests per minute (`429`).
            
Used by the embed login widget; the hosted Razor flow has its own
equivalent action on the AuthenticationController.

## Query parameters

- `data` unknown, required

## Response `200`

The recovery code was accepted; 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

- `400`: The recovery code was incorrect or missing (`invalid_grant`).
- `410`: The challenge expired (`challenge_expired`); restart the login.

---

[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)
