OTPBase
· OTPBase · 5 min de lecture

Letting an AI agent finish a 2FA login

Give an autonomous coding agent a task that involves logging into something, and it will get surprisingly far. It will find the login form, fill in the credentials, click submit — and then hit a wall. The site asks for a verification code, and the code is on your phone or in your email, somewhere the agent can't reach. So it stops and waits for a human. The fix is small: one read-only token and one line of instruction.

Where agents stall

Claude Code, Cursor, Operator, and the rest are good at multi-step work right up until a second factor enters the picture. The 2FA code lives outside the agent's world, and it has no way to ask for it that doesn't break the loop. The whole promise of an agent is that it finishes without you sitting next to it; the verification wall puts you right back in the chair.

OTPBase already has the code — it's the page where your forwarded codes land. The only thing missing is a way for the agent to read the latest one. That's exactly what the read API does.

The one call

Create a read-only token at /settings/api. It has the prefix otpb_ and the scope codes:read — it can read the latest code for a service and nothing else. Then the agent makes one request:

curl -s https://otpbase.com/api/v1/codes/latest?service=GitHub \
  -H "Authorization: Bearer otpb_your_token_here"

When there's an active code, you get it back with how long it has left:

{
  "code": "482913",
  "service": "GitHub",
  "received_at": "2026-05-28T14:02:11Z",
  "expires_at": "2026-05-28T14:17:11Z",
  "seconds_remaining": 838
}

When there's nothing active, you get a clean 404 so the agent can poll and wait:

{ "error": "no_active_code" }

That's the entire integration. No SDK, no callback URL, no webhook to host.

Telling the agent to use it

The agent just needs to know the call exists. A line in your .cursorrules or system prompt is enough:

When a login asks for a 2FA / verification code, fetch it from OTPBase:
  GET https://otpbase.com/api/v1/codes/latest?service=<SERVICE>
  Header: Authorization: Bearer ${OTPBASE_TOKEN}
Read the "code" field. If you get 404 no_active_code, wait a few
seconds and retry — the code may not have arrived yet.

In CI, the same thing works with the token kept as a secret. Here's a GitHub Actions step that reads the code and pulls out just the digits with jq:

- name: Fetch 2FA code
  env:
    OTPBASE_TOKEN: ${{ secrets.OTPBASE_TOKEN }}
  run: |
    code=$(curl -s "https://otpbase.com/api/v1/codes/latest?service=GitHub" \
      -H "Authorization: Bearer $OTPBASE_TOKEN" | jq -r '.code')
    echo "::add-mask::$code"
    echo "OTP_CODE=$code" >> "$GITHUB_ENV"

Why this is safe to hand an agent

Handing a machine your second factor sounds reckless, so it's worth being precise about what this token can and can't do.

The token gets the agent through the door. It doesn't decide which doors to open. A human still chooses what the agent logs into, what credentials it holds, and what it's allowed to do once inside. OTPBase only removes the one mechanical step that used to force a person back into the loop — and gives you a clean way to take it back the moment you want to.

Essayer OTPBase

Chaque code de vérification sur une seule page, appelable depuis une API. Gratuit pendant six mois — aucune carte pour commencer.

Obtenez un jeton — 6 mois gratuits
← Retour au blog