Skip to content
1Claw Academy
Curriculum/Advanced Security3 minAdvanced · Lesson 9 of 11

Human Factor Auth for treasury

Require a password or passkey from a real person before a treasury wallet can send, swap, or export.

Human Factor Auth (HFA, v0.56) puts a person in the loop on the operations that move money. Treasury wallet send, swap, and export can each require a password or a passkey before they proceed: regardless of what token the caller holds.

The policy resolves in a fixed order, most specific first:

  • The user's own human_factor_auth_policies.
  • Then human_factor_auth on the relevant wallet_spend_policies.
  • Then the system defaults.
Concept

HFA is about proving a human is present. It is deliberately separate from the agent guardrails in the Transactions track, which bound what an agent may attempt in the first place.

  1. 1

    Read the current policy.

    bash
    curl -s https://api.1claw.co/v1/auth/human-factor-auth \
      -H "Authorization: Bearer $ONECLAW_TOKEN"
  2. 2

    Require a passkey for sends and exports, and a password for swaps.

    bash
    curl -s -X PUT https://api.1claw.co/v1/auth/human-factor-auth \
      -H "Authorization: Bearer $ONECLAW_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "send":   { "method": "passkey" },
        "swap":   { "method": "password" },
        "export": { "method": "passkey" }
      }'
  3. 3

    Clients can prefetch the effective policy so they know which step-up to prompt for before the user hits send.

    bash
    curl -s https://api.1claw.co/v1/treasury/wallets/auth-policy \
      -H "Authorization: Bearer $ONECLAW_TOKEN"
  4. 4

    Satisfy the step-up. Mint a re-auth token, then present it on the protected call.

    bash
    curl -s -X POST https://api.1claw.co/v1/auth/reauth/begin \
      -H "Authorization: Bearer $ONECLAW_TOKEN" \
      -d '{"method":"passkey"}'
    # complete the ceremony, then send the resulting rat_ token:
    #   -H "X-Auth-Confirm: rat_..."
Tip

Two webhooks make HFA observable: human_factor_auth.satisfied and human_factor_auth.denied. A run of denials is a strong signal that something is trying to move funds without a human.

Watch out

Social-login users may have no password. If you require the password method they cannot satisfy it: have them enrol a passkey or TOTP at /settings/security first.

Where this goes wrong in practice. HFA is the control most sensitive to human factors, which is exactly why the failures are behavioural rather than technical.

  • The threshold is set where prompts are constant. A step-up that fires on every operation is satisfied reflexively within a week, and reflexive satisfaction is indistinguishable from no control.
  • A required factor cannot be presented. Social-login users have no password, so a password requirement is unsatisfiable rather than strict, and the failure looks like a bug rather than a policy choice.
  • Clients do not prefetch the policy. Without reading the effective policy first, the interface discovers the requirement by failing the send, which trains users to retry rather than to authenticate.
  • Denials are not monitored. human_factor_auth.denied is the signal that something is repeatedly attempting to move funds without a person, and it is worth an alert rather than a dashboard.
Tip

Sustained denials are more interesting than sustained approvals. Approval means the system is being used; denial means something is trying and failing, which is either a broken client or an attacker.

Decide

You set the HFA policy to require a password for treasury sends. A batch of users, all of whom signed up through Google, immediately cannot send at all.

What happened?

Check your understanding

3 questions
1

In what order does an HFA policy resolve?

2

Why prefetch GET /v1/treasury/wallets/auth-policy?

3

A social-login user has no password set. What breaks if the HFA policy requires the password method?