Beta access & desktop handshake

The Forven desktop app verifies beta access by calling the Forven entitlement API. This page describes how that handshake works, which is useful if you're integrating a custom build, debugging device links, or curious about what the app sends.

Overview

Linking uses an OAuth 2.0-style device-code flow. The desktop app generates a short user code, the user approves it at /activate while signed in, and a refresh token — an opaque bearer string that authenticates a single installation — is handed back to the desktop. The desktop stores the token in the OS keychain and calls GET /api/entitlement periodically to refresh its access state.

Endpoints

POST /api/devices/code

Auth: none (public). Response:

{
  "userCode": "FLPB-YMB9",
  "deviceCode": "dc_…",
  "expiresIn": 600,
  "interval": 2
}

The desktop displays userCode to the user and polls /api/devices/code/status with deviceCode.

GET /api/devices/code/status?deviceCode=<dc_…>

Auth: the deviceCode itself is the credential. Response while pending: { "status": "pending" }. Response after approval (one-time):

{
  "status": "approved",
  "deviceId": "uuid",
  "refreshToken": "fv_…"
}

The token is returned exactly once, on the first poll after approval. Subsequent polls return { "status": "consumed" }.

POST /api/devices/code/approve

Auth: web session cookie (Auth.js). Body: { "userCode": "FLPB-YMB9", "deviceName": "Desktop" }. Normally the /activate page server action calls the shared approveDeviceCode helper directly; this endpoint exists for desktop-adjacent tooling.

GET /api/entitlement

Auth: Authorization: Bearer <refreshToken>. Response during beta:

{
  "tier": "forged",
  "status": "beta",
  "currentPeriodEnd": null,
  "deviceId": "uuid",
  "offlineGraceHours": 72,
  "checkedAt": "2026-04-21T15:30:00.000Z"
}

For compatibility with current desktop builds, beta access reports tier: "forged" so the full product surface is unlocked. The status field marks that the account is on beta access.

GET /api/devices

List your linked devices.

DELETE /api/devices?id=<uuid>

Revoke a device. The desktop will fail its next entitlement check and require the device to be linked again.

Offline grace period

The desktop caches the last successful /api/entitlement response to disk. If it can't reach the server — bad Wi-Fi, travel, server outage — it keeps honoring the cached tier for offlineGraceHours (72 hours by default) past checkedAt.

This is a pragmatic tradeoff: users don't get locked out of their own research if we're down, and we don't need to ship a long-lived offline access file.

Security notes

  • Refresh tokens are long random strings stored in the DB and compared directly. Rotate by revoking and re-linking.
  • The token is the only credential needed to call /api/entitlement; treat it like a password.
  • Web session cookies cannot be used to call /api/entitlement; that endpoint accepts only bearer tokens. This keeps browser origins from being able to mint entitlement responses indirectly.