Authentication
The BeaconCR API uses OAuth 2.0 client credentials for server-to-server access. Clients are issued per organization, tokens are short-lived and org-scoped, and every call is authorized against the scopes granted to the client.
The client-credentials flow
A client ID and secret are issued to your organization from the admin interface (see getting started). Your server presents them at the token endpoint to receive a bearer token:
| Parameter | Value |
|---|---|
| Endpoint | POST https://<host>/api/v1/auth/token |
| Grant type | client_credentials |
| Client ID | Issued at client creation; not secret on its own |
| Client secret | Issued at client creation; shown once, stored hashed |
| Scope | Space-separated list of requested scopes (see below) |
| Token lifetime | At most 1 hour (returned as expires_in) |
curl -X POST "https://<host>/api/v1/auth/token" \
-H "Content-Type: application/json" \
-d '{
"grant_type": "client_credentials",
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET",
"scope": "studies:read"
}'Successful response (placeholder values):
{
"access_token": "YOUR_ACCESS_TOKEN",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "studies:read"
}Send the token on every subsequent request: Authorization: Bearer YOUR_ACCESS_TOKEN.
Scopes
Scopes are granted per client and are checked per request. A token can only use the scopes that were requested at token time and granted to the client. Reading patient-identifiable data requires the dedicated phi:read scope — responses only include PHI fields when the token carries it, and every such read is written to the audit trail.
| Scope | Grants |
|---|---|
studies:read | Read studies, sites, forms, visits, and study status |
studies:write | Create and update studies, sites, forms, and visits |
records:write | Write participant records and data points (with reason-for-change) |
epro:read | Read ePRO instruments, invitations, and submitted responses |
epro:write | Issue ePRO invitations and manage instrument delivery |
consent:read | Read consent status and download signed consent documents |
consent:write | Record consent events |
exports:create | Start export jobs and retrieve completed download URLs |
audit:read | Read the organization audit trail |
webhooks:write | Register and manage webhook endpoints |
phi:read | Include patient-identifiable fields in responses (audited) |
Organization scoping
Every token is scoped to a single organization — the one the client was issued to. There is no mechanism to widen a token across organizations, and no credential that reads another org's studies, participants, or audit events. If your integration works with more than one organization, each organization issues its own client and the tokens never cross. Calling GET /organizations/me is the reliable way to confirm which organization a token belongs to.
Token lifetime and refresh
Access tokens are short-lived: at most one hour. There is no refresh token in the client-credentials flow — when a token expires, the API returns 401 with the auth_invalid_token error code, and your integration simply requests a new one with the same credentials. Build the token request into your client library rather than caching tokens past their expires_in value.
- Cache the token in memory and reuse it until shortly before expiry — do not request a token per request; token requests are rate-limited like everything else.
- Treat any 401 as "get a new token once, then retry" — not as a reason to loop.
- A revoked client or rotated secret invalidates tokens at the next token exchange; existing tokens run out on their own schedule.
User-delegated access (PKCE)
For integrations that act on behalf of a user rather than on behalf of the organization itself, BeaconCR supports the OAuth 2.0 authorization-code flow with PKCE (Proof Key for Code Exchange). This is optional and is only needed when a product must operate with an individual user's permissions — for example, a partner tool whose actions should be attributed to a signed-in coordinator. Server-to-server integrations should stay on client credentials. Details of the authorization endpoints are published in the OpenAPI document linked from the API reference.