AnpherosAnpheros PlatformDevelopers

Authentication and OAuth

API keys, OAuth 2.1 with PKCE (SMART on FHIR standalone launch), OpenID Connect id_token, SMART v2 patient scopes, token lifetimes and the consent lifecycle.

Anpheros Platform accepts three kinds of credentials. Every request carries exactly one.

Credential Looks like Who Sees
API key sk_test_… (sandbox) / sk_live_… (production) a project's server the patients the project created (in sandbox, including its own copy of 30 synthetic patients)
OAuth access token at_… an application acting for one patient under a consent that patient only, within the granted SMART scopes
Firebase ID token JWT a developer in the dashboard, or a patient in "Connections" their own organisations / their own records

Send it as Authorization: Bearer <credential> (API keys also work as X-Api-Key).

API keys

OAuth 2.1 (SMART on FHIR, standalone launch)

Discovery: GET /.well-known/smart-configuration.

  1. GET /oauth/authorize?response_type=code&client_id=…&redirect_uri=…&scope=…&state=…&code_challenge=…&code_challenge_method=S256[&purpose=treatment][&patient=<pairwise id>][&lang=ro] Shows the hosted consent page. PKCE S256 is mandatory; the redirect_uri must be registered exactly.
  2. The patient signs in (Google or email via Firebase), chooses the record (own or a dependent's), the duration (30/90/180/365 days) and allows. The platform issues a one-time code (10 minutes).
  3. POST /oauth/token with grant_type=authorization_code&code=…&code_verifier=…&redirect_uri=…&client_id=… (confidential clients add client_secret). Response: access_token (30 min), refresh_token (30 days, rotating), patient (your pairwise id for the record), grant_id, scope.
  4. Refresh: grant_type=refresh_token. Each refresh token is single-use. Presenting a used refresh token revokes the whole chain (theft detection). A parallel duplicate of a refresh request is refused and may also revoke the chain, so never rotate concurrently.
  5. Revoke: POST /oauth/revoke (token + client_id). Revoking a refresh token also revokes its access tokens.

Token responses carry Cache-Control: no-store and Pragma: no-cache, as SMART requires.

OpenID Connect (openid fhirUser)

Ask for openid fhirUser alongside the patient scopes and the token response also contains an id_token: a JWT signed with RS256, with iss (the platform's base URL), sub (your pairwise id for the person), aud (your client_id), exp, iat and fhirUser — the absolute URL of the person's Patient resource, readable with the access token you just received. Discovery lives at GET /.well-known/openid-configuration; the public keys at GET /oauth/jwks (kid in the token header). The nonce parameter is not supported yet (it is optional in the authorization-code flow). launch/patient and offline_access are accepted; the patient field of the token response is the launch context.

Other grant types: client_credentials (confidential clients; behaves like an API key), and the first-party identity grant (trusted clients only).

Scopes

SMART v2 patient scopes: patient/<Type>.<cruds> with an optional ?category=<code> filter (the only filter the server enforces; any other filter is refused at authorize time). patient/*.rs reads everything; offline_access adds a refresh token. Patient demographics and the directory are always readable under a grant. A resource type outside the grant returns 403; a patient outside the grant returns 404.

Consent lifecycle

Consents expire automatically, can be revoked by the patient at any time (Connections screen / /me), and every read under a consent is logged with the application id. Webhooks consent.granted / consent.revoked notify the project.

Errors

401 unknown/expired credential · 403 the credential exists but may not do this · 404 the resource does not exist for you · 429 rate limited (Retry-After). See errors.md.