> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# 401 REAUTH_REQUIRED on destructive operations

> The re-auth challenge gate on irreversible operations: what the 401 means, how to mint the token, which endpoints need it, and the expiry behavior behind the retry loop you are seeing.

# 401 REAUTH\_REQUIRED on destructive operations

The full handshake is deliberate. A `401 REAUTH_REQUIRED` means the gateway
stopped an irreversible operation (workspace deletion, GDPR erasure of a
contact, HIPAA disable, force-transfer of a conversation, 2FA disable,
backup-code regeneration) because the request did not carry a fresh
challenge token or carried one that was expired, already consumed, minted
for a different scope, or minted through the wrong namespace. This page
decodes the reject, shows the mint → carry → consume sequence, and names
the exact fix for each symptom.

If a full page about the model is what you need (the namespaces, the
binding key, and the coverage matrix), read
[Destructive-operation re-auth challenge](/concepts/re-auth-challenge-model).
This page exists so a customer who just hit the reject lands on the fix,
not on the theory.

## Symptom → fix table

| Symptom                                                                         | Fix                                                                                                                                                                               |
| ------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| First call to the gated endpoint, header never attached → `401 REAUTH_REQUIRED` | Mint a challenge first with POST to the mint endpoint, then re-send the gated request with the `X-Reauth-Challenge` header carrying the returned token.                           |
| Minted the token, still `401`                                                   | Check the `X-Reauth-Challenge` header name (exact, case-insensitive, no `Bearer` prefix, token verbatim) and that mint and consume share a route family.                          |
| Mint worked once, now every mint returns `401 CREDENTIAL_REQUIRED`              | The step-up gate (2FA verbs) requires the current password or a current TOTP code in the mint body. Supply the correct credential.                                                |
| Retry loop: mint → gated call → 401 → mint again → 401                          | The consume burned the token or the window (5 minutes) closed before the consume landed. Mint once per attempt, carry the token, consume within the window. Never reuse a token.  |
| Token minted against workspace A, gated on workspace B                          | The binding key pins the challenge to the target. Mint against the actual workspace or contact id.                                                                                |
| Token minted for HIPAA disable presented to a 2FA verb (or vice versa)          | The session-recency and step-up namespaces are deliberately separate. Mint through the endpoint that matches the gated verb.                                                      |
| Workspace deletion returns `401` even with a rich session                       | Deleting the workspace is the one verb the dashboard gates behind the challenge but a confirmed-slug deletion path also hard-blocks. If you are integrating directly, mint first. |
| HIPAA disable returns `401` on the dashboard                                    | Clicking disable runs the mint + carry invisibly. If the prompt rejects, the mint failed at the credential stage. Supply the password or TOTP in the dialog and retry.            |

## Full-error sample (paste-ready)

```json theme={null}
{
  "error": {
    "code": "REAUTH_REQUIRED",
    "message": "Fresh re-authentication is required to disable HIPAA mode. POST /settings/hipaa/reauth-challenge first, then retry within 5 minutes with X-Reauth-Challenge header."
  }
}
```

The `message` names the exact mint endpoint and the carry header. When you
open a ticket, include the `error.details` (op, mint endpoint) and the
request id from the response envelope.

## The mint → carry → consume sequence

1. **Mint.** From an authenticated session, POST the mint endpoint for
   the gated verb (the table below). The response carries the challenge
   token verbatim and its expiry timestamp, five minutes from issue.
2. **Carry.** Attach the token to the gated request in the
   `X-Reauth-Challenge` header, verbatim, with no `Bearer` prefix.
3. **Consume.** The gated endpoint burns the token atomically before
   doing any work. A second consume of the same token finds nothing. That
   is how a retry cannot double-execute the verb.

```bash theme={null}
# 1. Mint
curl -X POST "https://api.orbit.devotel.io/api/v1/settings/hipaa/reauth-challenge" \
  -H "Authorization: Bearer <session>" \
  -H "Content-Type: application/json" \
  -d '{}'

# -> { "challenge_token": "<token>", "expires_at": "<ISO>" }

# 2. Carry + consume
curl -X PUT "https://api.orbit.devotel.io/api/v1/settings/hipaa" \
  -H "Authorization: Bearer <session>" \
  -H "X-Reauth-Challenge: <token>" \
  -H "Content-Type: application/json" \
  -d '{"enabled": false}'
```

## Which mint endpoint for which gated verb

| Gated verb                                            | Mint endpoint                               | Proof at mint                |
| ----------------------------------------------------- | ------------------------------------------- | ---------------------------- |
| `DELETE /organizations/{id}`                          | `POST /organizations/{id}/reauth-challenge` | Active session               |
| `DELETE /contacts/{id}/gdpr/delete`                   | `POST /contacts/{id}/gdpr/delete/challenge` | Active session               |
| `PUT /settings/hipaa` with `enabled: false`           | `POST /settings/hipaa/reauth-challenge`     | Active session (owner)       |
| `POST /conversations/{id}/assign` with `force: true`  | `POST /settings/inbox/reauth-challenge`     | Active session (admin/owner) |
| `POST /settings/security/2fa/disable`                 | `POST /settings/security/2fa/challenge`     | Password or TOTP             |
| `POST /settings/security/2fa/backup-codes/regenerate` | `POST /settings/security/2fa/challenge`     | Password or TOTP             |

Session-recency and step-up tokens never satisfy each other's gates; the
2FA verbs are the only ones that accept the step-up namespace.

## Expiry and single-use semantics

* **Five-minute window.** Tokens die five minutes after mint, regardless
  of use. The window starts at mint, not at the arrival of the gated
  request.
* **Single-use.** The consume step burns the token atomically; a network
  retry or duplicate click cannot double-execute the verb.
* **Binding key.** Where the verb targets one resource, the token is
  pinned to the target identifier. A challenge minted against workspace A
  cannot authorize the deletion of workspace B; a challenge minted
  against contact 1 cannot erase contact 2.
* **Namespace split.** Session-recency mints (workspace, contacts, HIPAA,
  inbox force-transfer) and step-up mints (2FA verbs) are two separate
  token pools, deliberately incompatible.
* **Fail-closed.** Any doubt (missing header, expired token, consumed
  token, wrong namespace, wrong target, wrong proof) is a rejection. The
  store the gate consumes from is queried in a single atomic operation;
  if that store is unreachable, the gate rejects rather than lets
  destruction proceed.

## Decision checklist

1. **Is this the first attempt at this call?** If yes, mint the challenge
   first. If no, skip to the header check.
2. **Is the gated verb in the table above?** If the verb is not listed,
   the reject is a different error class; match `error.code` against
   [Error codes](/reference/error-codes).
3. **Is the header name exactly `X-Reauth-Challenge`?** No `Bearer`, no
   encoding, no surrounding quotes.
4. **Did the mint respond with a token in the last five minutes?** If
   not, mint again.
5. **Was the token minted against the same workspace / contact / route
   family?** If not, mint against the actual target.
6. **On a 2FA verb (disable, backup codes): did the mint ask for a
   password or TOTP and did you supply the correct credential?** Supply
   one and retry.
7. **Is the dashboard involved?** The dashboard completes the handshake
   invisibly; if a dialog rejects, treat the mint stage as the failure,
   not the gated call.

## What NOT to do

* **Do not loop the retry on an expired token.** Re-mint first; an
  expired token can never be re-attached.
* **Do not smuggle the token through a `Bearer` scheme.** The header
  carries the token verbatim; a scheme prefix burns the consume.
* **Do not strip the `Idempotency-Key` from the gated call.** The
  challenge enforces single-use; idempotency dedupes retry-vs-retry.
* **Do not route a session-recency verb through the step-up challenge**
  (or the reverse). The mint endpoints are distinct routes because the
  proof at mint differs.
* **Do not file the whole workspace delete behind an API key.** The
  session-recency gate requires an authenticated user session; API keys
  cannot mint this challenge. Mint via the dashboard or a user session.

## When to escalate

Escalate when the gate fails on a flow the dashboard has already run
invisibly (the prompt rejected the mint), when a token minted seconds ago
is rejected as expired, or when a workspace-delete mint that you watched
succeed returns `401` on the consume. Attach the request id from the
error envelope, the mint endpoint URL, and the `details` payload.

## See also

* [Destructive-operation re-auth challenge model](/concepts/re-auth-challenge-model):
  the namespaces, the binding key, and the coverage matrix this gate
  serves.
* [Account security model](/concepts/account-security-model): the 2FA,
  backup codes, and require-2FA bitmap the step-up namespace protects.
* [HIPAA blocked until the BAA is executed](/troubleshooting/hipaa-enable-baa-not-executed):
  the 403 on a HIPAA enable while the BAA is pending; the re-auth gate is
  the 401 on the disable, not the enable.
* [Error Code Reference](/reference/error-codes): the fall-through for
  any `code` this page does not map.
