TEASEDocs
ProductsAccount Platform

API — Native login

How the desktop app pairs a device and gets a token — an OAuth-authorization-code-and-PKCE-shaped flow with a device signature bolted on, plus its own in-app consent screen and lost-device recovery.

These endpoints issue and refresh the device-bound grant that every Browser runtime call is authenticated against. Mounted by build_browser_native_authorization_router and build_browser_native_management_router (app/products/platform/api/ browser_native_authorization.py) plus build_browser_engine_receipt_router (browser_engine_receipt.py), all composed via compose_browser_native (app/main.py:126-130).

Not a full protocol spec

This page describes the contract an integrator needs — paths, methods, error codes. It does not reproduce field-level signature and challenge formats; those are treated the same as the rest of our security posture, described at the results level. See Security for that framing.

Authorization code exchange

EndpointMethodNotes
/api/auth/browser-native/authorizeGETShows the external consent page. Exists only when the routes_enabled policy flag is on.
/api/auth/browser-native/authorizePOSTRecords the consent decision, issues the authorization code, 303-redirects back to the app with code and state.
/api/browser-native/v1/consent/contextPOSTSame consent dialog, shown inside the panel instead of via an external navigation — added after Cloudflare's SSRF rule blocked the external page's redirect to a 127.0.0.1 callback.
/api/browser-native/v1/consentPOSTRecords the decision for the in-panel flow.
/api/browser-native/v1/tokenPOSTExchanges the code for a grant. Accepts either the current encoded envelope ({"request": "<base64url>"}) or the older flat body — both resolve to the same exchange, so existing installed builds keep working.

Both consent paths share the same boundary checks (exact-origin request validation, device-signature verification, replay protection on the code) — the in-panel path is not a weaker shortcut, just a different transport for the same dialog. A replayed authorization code returns 409 authorization_operation_replayed; a denied consent redirects back with error=access_denied rather than an HTTP error.

Challenges, refresh, revoke

  • POST /api/browser-native/v1/challenges — issues a signed challenge the app uses to build its next proof. Same shape as /challenges on the Browser runtime page — two issuance points for the same primitive, one per phase.
  • POST /api/browser-native/v1/refresh — refreshes the grant, proof-authenticated.
  • POST /api/browser-native/v1/revoke — revokes the current installation, proof-authenticated.
  • GET /api/browser-native/v1/config — public bootstrap config for the desktop app (no auth).

All three of challenges/refresh/revoke fail closed to a single generic invalid_grant error rather than distinguishing why a grant failed — intentional, not an oversight: the failure reason is not handed back over the wire.

Lost-device recovery

POST /api/me/browser-installations/{device_installation_id}/revoke — revokes an installation using the panel session cookie, not a device proof. This is the recovery path for a lost or stolen laptop: the person signs into the panel from anywhere and kills the old installation without needing the device itself. Returns 404 not_found if the installation doesn't belong to the caller.

Engine identity receipts

POST /api/browser-native/v1/engine-identity-receipts activates a browser profile from a signed receipt the sync engine issues, verified via the X-Engine-Receipt-Signature header. 401 invalid_engine_identity_receipt on a bad/expired signature; 409 (via the shared connect-family error mapping) on a conflicting activation state.

A second, separate mount for the same receipt shape

POST /api/connect/browser-profiles/identity-receipt (documented on API — Connecting an account) accepts the same EngineReceiptBody and the same signature header, but is a distinct route reached through the connect flow rather than this one. Check the full path, not just the body shape, when reading a log line.

What's next

Once a grant is issued, see API — Browser runtime for what the app does with it.

On this page