Skip to content

Authentication

Two paths. Pick whichever matches the caller.

PathHeader / cookieCapability source
JWT cookieCookie: session=… (set on login)Membership role on the active org
API keyAuthorization: Bearer one_pk_…The key's scopes array

If both are present, the API key takes precedence.

This is what the web app uses. Sign in at /login or via Google OAuth and the browser sends the cookie automatically. Capabilities follow the user's membership role on the currently-active org:

RolePublic (metrics.read)Privileged (people.view_cost, people.view_paygap)
owner
admin
member
contractor

If you switch organisations in the app, every subsequent API call is scoped to the new org.

API keys

Mint at Settings → API Keys. Each key is scoped to one (user, org) pair and carries an explicit list of capabilities — the boxes you tick at creation time.

Format

one_pk_<32 chars of base64url>

The first 8 chars after one_pk_ are the public prefix, shown in the UI so you can identify which key is which without ever revealing the secret. The full string is hashed (SHA-256) before storage; we cannot recover it once you've closed the dialog.

Use

sh
curl -H "Authorization: Bearer one_pk_BzXzIiYbQ4UI…" \
  "https://app.okavango.io/api/v1/metrics"

Scope policy

When a request authenticates via API key, the key's scopes are the only grants beyond public. The underlying user's role is ignored — a key minted by an owner does not inherit owner privileges. This means:

  • A metrics.read-only key sees finance metrics, headcount, growth, diversity — but not comp.* or paygap.*
  • To grant compensation visibility, tick people.view_cost at creation
  • To grant pay-equity visibility, tick people.view_paygap at creation
  • A key with all three boxes ticked still doesn't carry capabilities you didn't tick — there are no implicit grants

This matches how API keys work in most modern platforms (GitHub PATs, Stripe restricted keys): explicit scopes, never role inheritance.

Revoke

Settings → API Keys → Revoke. Revocation is immediate — every subsequent request returns 401 UNAUTHENTICATED from the next call onwards.

Errors

CodeStatusMeaning
UNAUTHENTICATED401No cookie, missing / malformed Authorization header, unknown or revoked key
FORBIDDEN_CAPABILITY403Authenticated, but lacks the capability the metric requires

See error catalogue for the full list.

OneBusiness · Built for businesses that work.