---
title: "Set WebAuthn two-factor authentication"
method: PUT
path: "/users/@me/mfa/webauthn/two-factor"
tags: ["Users"]
---

# Set WebAuthn two-factor authentication

`PUT /users/@me/mfa/webauthn/two-factor`

Choose whether registered passkeys are required as a second factor when signing in with email and password. Enabling requires at least one registered credential and mints backup codes when the account has none. Requires sudo mode verification.

## Request body

- WebAuthnTwoFactorRequest
  - `enabled` boolean, required — Whether registered passkeys count as a second factor when logging in
  - `password` string
  - `mfa_method` 'totp' | 'webauthn' — MFA method to use for verification
  - `mfa_code` string — MFA verification code from an authenticator app
  - `webauthn_response` WebAuthnAuthenticationResponse
    - `id` string, required
    - `rawId` string, required
    - `type` 'public-key', required
    - `authenticatorAttachment` 'cross-platform' | 'platform'
    - `clientExtensionResults` object, required
      - `appid` boolean
      - `credProps` object
        - `rk` boolean
      - `hmacCreateSecret` boolean
    - `response` object, required
      - `clientDataJSON` string, required
      - `authenticatorData` string, required
      - `signature` string, required
      - `userHandle` string
  - `webauthn_challenge` string — WebAuthn challenge string

## Response `200`

Success

- WebAuthnTwoFactorResponse
  - `user` UserPrivateResponse, required
    - `id` string, snowflake, required
    - `username` string, required — The username of the user, not unique across the platform
    - `discriminator` string, required — The four-digit discriminator tag of the user
    - `global_name` string, nullable, required — The display name of the user, if set
    - `avatar` string, nullable, required — The hash of the user avatar image
    - `avatar_color` integer, required
    - `bot` boolean — Whether the user is a bot account
    - `system` boolean — Whether the user is an official system user
    - `flags` integer, required — The public flags on the user account
    - `mention_flags` 0 | 1 | 2 — Reply mention preference
    - `is_staff` boolean, required — Whether the user has staff permissions
    - `acls` string[], required — Access control list entries for the user
    - `traits` string[], required — Special traits assigned to the user account
    - `email` string, nullable, required — The email address associated with the account
    - `email_bounced` boolean — Whether the current email address is marked as bounced by the mail provider
    - `phone` string, nullable — Always null. Retained for old-client backward compatibility — phone numbers are no longer stored on the user record.
    - `has_verified_phone` boolean, required — Whether this account has completed phone verification
    - `bio` string, nullable, required — The user biography text
    - `pronouns` string, nullable, required — The preferred pronouns of the user
    - `accent_color` integer, required
    - `timezone` string, nullable — The IANA timezone identifier saved by the user. Omitted unless the user has staff access.
    - `timezone_privacy_flags` integer — Bitfield controlling who can see the profile timezone
    - `banner` string, nullable, required — The hash of the user profile banner image
    - `banner_color` integer, required
    - `mfa_enabled` boolean, required — Whether multi-factor authentication is enabled
    - `authenticator_types` UserAuthenticatorTypes[] — The types of authenticators configured for MFA
    - `verified` boolean, required — Whether the email address has been verified
    - `premium_type` 0 | 1 | 2, required — Premium subscription type
    - `premium_since` string, nullable, required — ISO8601 timestamp of when premium was first activated
    - `premium_until` string, nullable, required — ISO8601 timestamp of when premium access ends, including stacked gift time
    - `premium_will_cancel` boolean, required — Whether premium is set to cancel at the end of the billing period
    - `premium_billing_cycle` string, nullable, required — The billing cycle for the premium subscription
    - `premium_lifetime_sequence` integer, required
    - `premium_grace_ends_at` string, nullable, required — ISO8601 timestamp at which the post-cancel grace period ends. Set when the subscription is fully canceled in Stripe; perks remain active and the original premium_since is restored on resubscribe until this timestamp passes. Null when not in grace.
    - `premium_discriminator` boolean, required — Whether the user selected a premium-only discriminator that will be rerolled when non-lifetime premium access ends
    - `premium_badge_hidden` boolean, required — Whether the premium badge is hidden on the profile
    - `premium_badge_masked` boolean, required — Whether the premium badge shows a masked appearance
    - `premium_badge_timestamp_hidden` boolean, required — Whether the premium start timestamp is hidden
    - `premium_badge_sequence_hidden` boolean, required — Whether the lifetime sequence number is hidden
    - `premium_purchase_disabled` boolean, required — Whether premium purchases are disabled for this account
    - `premium_enabled_override` boolean, required — Whether premium features are enabled via override
    - `premium_perks_disabled` boolean, required — Whether premium perks are temporarily disabled for this account
    - `force_inbound_phone_verification` boolean — Whether this account is forced through the inbound (expensive-destination) phone verification flow regardless of prefix, for debugging
    - `password_last_changed_at` string, nullable, required — ISO8601 timestamp of the last password change
    - `last_voice_activity_sharing_change_at` string, nullable, required — ISO8601 timestamp of the last bulk voice-activity-sharing change. Drives the 24-hour cooldown for re-toggling the Active Now sharing default.
    - `required_actions` string[], required — Actions the user must complete before full access
    - `nsfw_allowed` boolean, required — Whether the user is allowed to view NSFW content
    - `has_dismissed_premium_onboarding` boolean, required — Whether the user has dismissed the premium onboarding flow
    - `has_ever_purchased` boolean, required — Whether the user has ever made a purchase
    - `has_unread_gift_inventory` boolean, required — Whether there are unread items in the gift inventory
    - `unread_gift_inventory_count` integer, required
    - `pending_bulk_message_deletion` object, nullable, required — Information about a pending bulk message deletion request. Only populated when the legacy delayed-deletion flow is in progress; the new immediate-deletion flow does not surface a pending state here.
      - `scheduled_at` string, required — ISO8601 timestamp of when the deletion was scheduled
      - `channel_count` integer, required
      - `message_count` integer, required
    - `age_verified_adult` boolean — Whether the user has verified their age as an adult via credit card verification
    - `terms_agreed_at` string, nullable, required — ISO8601 timestamp of when the user last agreed to the terms of service
    - `privacy_agreed_at` string, nullable, required — ISO8601 timestamp of when the user last agreed to the privacy policy
  - `backup_codes` object[], nullable, required — Backup codes minted by this call, or null when none were minted
    - `code` string, required — The backup code
    - `consumed` boolean, required — Whether the code has been used

## Other responses

- `400` — Bad Request - The request was malformed or contained invalid data
- `401` — Unauthorized - Authentication is required or the token is invalid
- `403` — Forbidden - You do not have permission to perform this action
- `429` — Too Many Requests - You are being rate limited
- `500` — Internal Server Error - An unexpected error occurred

## Changes

> 15 revisions in range; 1 not diffed.

- **2026-09-20** `5296f41cd55d` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/fluxer/apis/fluxer-api/changes/users/@me/mfa/webauthn/two-factor/put.md)

---

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