Authentication
userGist uses separate credentials for untrusted mobile clients, trusted customer backends, and dashboard operators.
| Surface | Used by | Credential |
|---|---|---|
SDK (/v1/sdk/*) | Shipped mobile clients | Client write key (rk_live_...) plus an app-scoped subject token |
| Server API (identity exchange and transactional push) | Your trusted backend | Server key (rtk_...) with the narrow required scope |
Dashboard (/v1/apps/*, /v1/workspaces/*) | Signed-in dashboard operators | WorkOS access token with workspace role checks |
Write keys
A write key is a public, per-app mobile credential. It selects the app but is not proof of a user's identity. The SDK establishes an anonymous subject session and sends its scoped subject token on identity-bearing requests.
POST /v1/sdk/ingest HTTP/1.1
Host: api.usergist.com
Authorization: Bearer rk_live_abcdef1234567890
X-UserGist-Subject-Token: st_anonymous_session_token
Content-Type: application/json
{ "events": [...], "context": { "anonymousId": "...", "sdkVersion": "...", "platform": "react-native" } }- Header:
Authorization: Bearer <write-key>. - Formats:
rk_live_...,rk_stg_..., orrk_dev_.... - Stored on the server as
sha256(<plaintext>); never recoverable. - Rotated from App settings → SDK keys. See Admin → Write keys.
The SDK includes platform, SDK-version, and host-app-version metadata in its request context. Those fields support diagnostics and analytics; they are not credentials and do not decide which SDK package the client runs.
Identified subjects
Never let a mobile caller prove identity by supplying only an external user ID.
Your authenticated backend calls
POST /v1/apps/:appId/sdk/subject-tokens with a server key carrying the
sdk:subjects scope, then returns the opaque st_... token to that user.
Derive externalId from the authenticated server session—not an untrusted body field.
const response = await fetch(
'https://api.usergist.com/v1/apps/YOUR_APP_ID/sdk/subject-tokens',
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.USERGIST_SERVER_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ externalId: String(session.user.id) }),
},
)
if (!response.ok) throw new Error('Identity exchange failed')
const { data } = await response.json()
// Return data.subjectToken to this authenticated app user only.Pass data.subjectToken with the matching external ID to the SDK's identify method. Unidentified installations do not need this backend exchange. A guest with a backend account ID can use the same identified flow. The response includes expiresAt; the default lifetime is 90 days, configurable by the UserGist server. See account identity and logout for refresh, property deletion, completion APIs, and release availability.
Server keys
Owners and admins create server keys under Workspace → Server keys. Plaintext is shown once and only its SHA-256 hash is retained. Keys are scoped, expire after at most one year, expose a last-used timestamp, and can be revoked immediately. Use sdk:subjects for identified-user exchange and push.transactional for backend-triggered transactional delivery; combine them only when the same backend genuinely needs both.
Authorization: Bearer rtk_your_server_keyNever embed an rtk_... key in a mobile app, browser bundle, repository, or build artifact. Store it in a backend secrets manager and rotate it before expiry.
Dashboard access
The dashboard obtains a WorkOS access token after sign-in. API routes enforce workspace membership and the required role (viewer, editor, admin, or owner) on every request. Client write keys and server keys cannot call dashboard endpoints.
Rate limits
Per-app, per-credential, returned as headers:
RateLimit-Limit: 1000
RateLimit-Remaining: 942
RateLimit-Reset: 12Plan-based defaults:
| Plan | Sustained / s | Burst |
|---|---|---|
| Starter | 100 | 500 |
| Pro | 1k | 5k |
| Enterprise | Negotiated | Negotiated |
Hitting the limit returns 429 Too Many Requests with a Retry-After header. The SDKs respect it with exponential backoff.
Transport security
The React Native SDK uses platform HTTPS trust for api.usergist.com.
Application-level SPKI/certificate pinning is not currently implemented. If
your threat model requires pinning, enforce it in the host application and
maintain a tested backup-pin/rotation procedure.
Errors
Every error follows the envelope in API → Errors. For auth specifically:
| Status | Meaning |
|---|---|
401 unauthenticated | Missing or unknown credential. |
403 forbidden | Credential is valid but lacks scope (e.g. write key trying to read users). |
429 rate_limited | See Retry-After. |