API
Sign-in approvals
The Authenticator app's side of sign-in approvals: requests waiting for an answer, the signed answer, enrolling the phone's key, and signing out everywhere after No.
See Sign-in approvals. These routes are at /v1/me/sign-in-approvals, reachable only with the Authenticator app's own sign-in (a mobile token issued to the authenticator app): organization keys, Caity, the phone assistant and the other apps get 403. A token alone can read requests but can't answer them: answers, enrolling and signing out everywhere carry a signature from the phone's key.
Keys. Each phone has a P-256 key (on iPhone, made in the Secure Enclave). Public keys are the 65-byte uncompressed point in base64url; signatures are ECDSA with SHA-256 over the UTF-8 message, DER-encoded, in base64. Every message is one field a line:
si-sign-in-approval/v1
approval:<approvalId>
user:<userId>
device:<deviceId>
decision:<approve | deny>
number:<the number tapped, or ->
binding:<the request's binding>
expires:<the request's expiresAt>Enrolling signs si-sign-in-approval-enrol/v1, user:, key: (the public key) and signed: (epoch milliseconds, within 5 minutes of the server's clock); signing out everywhere signs si-sign-in-approval-secure/v1, user:, device:, approval: (the request answered with No) and signed:.
Enrolling needs the app's sign-in to be recent (10 minutes) and made with a passkey or a password and a second step; otherwise 403 with code: "reauth", and the app signs in again with prompt=login.
Answering. The right number approves; another number or deny denies. A request can be answered once, before its expiresAt (2 minutes after it was made); the third denial in 15 minutes pauses requests for an hour (paused: true). Answers are limited to 20 per account in 15 minutes, signatures that don't verify included.
Every route below, with its parameters, request and response, errors and samples, is in the API reference.
| Route | What it does |
|---|---|
GET /v1/me/sign-in-approvals/settings | Sign-in approvals for your account: on, pausedUntil (epoch ms, while requests are paused after denials), the phones that approve (devices: name, model, system, where the key lives, when added and last used; never keys) and twoStep (whether the account has a code to fall back to; requests need one). From the Authenticator app's sign-in only. |
GET /v1/me/sign-in-approvals/requests | Sign-in requests waiting for an answer, newest first: what's signing in (app), from which browser (device), roughly where (place), createdAt and expiresAt. No numbers. What the app shows when it opens, for a notification that never arrived. |
GET /v1/me/sign-in-approvals/requests/:approvalId | One waiting request with the three numbers to show (choices), the account (userId, email) and the binding the answer is signed with; 404 once answered, withdrawn or expired. |
POST /v1/me/sign-in-approvals/requests/:approvalId | Answers a request from this phone (deviceId): decision approve with the number tapped, or deny, with signature (see above). The right number approves; another number or deny denies (reason wrong_number or not_me, and paused when requests are now paused for an hour). 403 when the signature doesn't verify or the phone was removed, 409 when already answered or expired, 429 past 20 answers in 15 minutes. |
POST /v1/me/sign-in-approvals/devices | Enrols this phone's key: publicKey, keyStorage (secure-enclave, keychain or keystore), name, optional model, os, appVersion, installId, timeZone, with signedAt and the key's signature over the enrolment message. 201 with the device (200 for a key already enrolled); the same phone's older key is replaced; up to 10 phones. 403 with code: "reauth" until the app's sign-in is recent and two-step or a passkey. Turns approvals on. |
DELETE /v1/me/sign-in-approvals/devices/:deviceId | Removes a phone: it gets no more requests and its answers are refused. |
POST /v1/me/sign-in-approvals/secure | Signs your account out everywhere but this app, after this phone answered a request with No (approvalId, within 30 minutes): every browser session at ID with the web apps' sign-ins from them, every other phone app and every command-line sign-in. Signed with the phone's key (deviceId, signedAt, signature). Returns how many browsers, apps and commandLine sign-ins ended. |