Polyester uses multi-factor authentication (MFA) to protect interactive sessions. Routine requests use the session token created at login. Sensitive operations require stronger proof: either a recent MFA-elevated session or a fresh, single-use step-up.
Factors
- Passkeys use WebAuthn and a device credential such as Face ID, Touch ID, Windows Hello, a laptop PIN, or a hardware security key.
- TOTP uses a time-based code from an authenticator app.
- Recovery codes are one-time backup credentials. Store them offline or in a password manager.
The first enrolled factor creates the account's recovery codes. Adding another factor requires
proof from an existing factor. After TOTP or passkey enrollment succeeds, replace the current bearer
token with the returned access_token. The enrollment response also includes session and access_token_expires_at.
Session assurance
| Requirement | Client credential | Validity |
|---|---|---|
| Primary session | Bearer token created at login | Routine authenticated access |
| Recent MFA session | MFA-elevated bearer token | 30 minutes from MFA completion |
| Fresh step-up | Separate step_up_token sent in X-Auth-Step-Up | One protected action |
A fresh step-up is bound to the interactive account and session. The proof is not reusable, but
successful verification also returns an independent MFA-elevated access_token for subsequent
Recent MFA requirements.
Completing a challenge
When an endpoint requires a fresh proof:
- Call
BeginMFAChallengewithMFA_CHALLENGE_PURPOSE_FRESH_STEP_UP. - Verify the challenge with TOTP
(
VerifyTOTPChallenge), a passkey (FinishPasskeyChallenge), or a recovery code (VerifyRecoveryCodeChallenge). - Replace the current bearer token with the returned
access_token. - Retry the original request with the returned
step_up_tokeninX-Auth-Step-Up.
For endpoints that accept a recent MFA session, use MFA_CHALLENGE_PURPOSE_SESSION_ELEVATION instead and replace the bearer token with the returned
MFA-elevated access_token. Both challenge purposes return session, access_token, and access_token_expires_at. A Fresh Step-Up response additionally returns step_up_token and step_up_expires_at.
Endpoint reference
The following lists give the MFA requirement of each API method. The REST and ConnectRPC references provide the transport-specific paths.
Recent MFA session required
- Address book entries ·
CreateAddressBookEntry,UpdateAddressBookEntry,DeleteAddressBookEntry,CopyAddressBookEntry
With an enrolled factor, MFA completed within the previous 30 minutes satisfies the requirement.
When no factor is enrolled, address-book entry mutations do not prompt for MFA. After enrollment, elevate the session again when its recent-MFA window expires.
Fresh step-up required
- API keys ·
CreateApiKey,UpdateApiKey,DeleteApiKey
Creating a key also requires MFA enrollment. Every API key update is protected. - Subaccount policies ·
CreateSubaccountPolicy,UpdateSubaccountPolicy,DeleteSubaccountPolicy,SetSubaccountPolicy
Setting a policy includes attaching or clearing it. - API key policies ·
CreateApiPolicy,UpdateApiPolicy,DeleteApiPolicy,SetApiKeyPolicy
Creating and assigning a policy in one request uses one proof. - MFA security ·
DeleteMFAFactor,RegenerateRecoveryCodes
The last factor cannot be deleted. Regeneration invalidates previous recovery codes. - Subaccount members ·
InviteSubaccountMember,UpdateSubaccountMemberRole
The owner's role cannot be changed; such calls fail withAUTH_SUBACCOUNT_OWNER_ROLE_LOCKED. - GuardSigner approvals ·
SignProtectedAction,BatchSignProtectedActions
Required for supported external and internal whitelist mutations. A batch needs one when any item is protected. - GuardSigner wallet ·
RotateGuardSignerWallet,ExportGuardSignerWallet
Both require MFA enrollment. - Auto-withdraw rules ·
SetAutoWithdrawRule,DisableAutoWithdrawRule
Refused to every API key, whatever its policy.
Conditional requirements
- Factor enrollment ·
BeginTOTPEnrollment,BeginPasskeyEnrollment
Fresh step-up is required when the account already has a factor. The first factor is exempt. - Finish enrollment ·
FinishTOTPEnrollment,FinishPasskeyEnrollment
Additional-factor enrollment must follow a begin request that validated step-up. Successful completion returns a new MFA-elevated access token. - Member MFA policy ·
SetSubaccountMemberMFARequirement
Disablingrequire_member_mfarequires fresh step-up. Enabling it does not. - Remove member ·
RemoveSubaccountMember
Removing another member requires fresh step-up. Leaving the Subaccount yourself does not. - Respond to invite ·
RespondSubaccountInvite
Accepting requires enrollment and Recent MFA whenrequire_member_mfa=true. Declining or cancelling does not. - Wallet withdrawal ·
CreateWalletTradingWithdraw
Trading-to-Funding moves and withdrawals to explicitly whitelisted external destinations by the Main Account owner accept a recent MFA session. Delegated and other interactive movements require fresh step-up. An existing idempotent intent requires no new proof. - Internal transfer ·
CreateInternalTransfer
Transfers by the Main Account owner within the same ownership tree, or to explicitly whitelisted destinations, accept a recent MFA session. Delegated and other interactive transfers require fresh step-up. API key requests are exempt.
Similar endpoints that do not require MFA
CreateTradingWithdrawis API-key-only. It requires a signed payload and the relevant policy permission.- API-key-authenticated internal transfers do not use interactive MFA.
CreateGuardSignerWalletandGetGuardSignerStatusdo not require MFA.- Read-only API key, policy, address-book, destination, and whitelist methods do not require MFA.
- Order placement, amendment, and cancellation do not require MFA.
API key sessions cannot satisfy an interactive MFA requirement. Where an API key is not explicitly exempt, the endpoint rejects that session type.
Every method that accepts only a session token refuses an account API key, or a session token that
carries one, the same way: HTTP 403 with the code AUTH_SESSION_KIND_NOT_ALLOWED and the detail interactive session required. REST returns the code in its application/problem+json body;
ConnectRPC answers permission_denied with an auth.v1.AuthErrorDetail carrying the code. The API
reference marks these methods "Session token".
See Withdrawals and Transfers Security for the complete money-movement model.
MFA, signatures, and whitelists
These controls solve different problems:
- MFA confirms that the interactive user is present.
- A wallet or API key signature binds the Asset, amount, source, destination, nonce, and expiry.
- A whitelist limits where funds may move.
Protected money-movement flows can require more than one of these checks.