Skip to main content

Obtaining tokens

Every request to an ARC endpoint carries an OAuth2 bearer access token. Tokens are issued by Osigu's SSO server via the client-credentials grant — no user login flow, no refresh tokens, no PKCE. You have a client_id, a client_secret, and you exchange them for an access token you cache and reuse.

The one endpoint you'll call

POST /v1/oauth/token on Osigu's SSO server. Same shape in both environments — only the host differs:

EnvironmentHost
Sandboxhttps://sandbox.osigu.com
Productionhttps://api.osigu.com

Full URL for sandbox: https://sandbox.osigu.com/v1/oauth/token.

Request

Standard OAuth2 client-credentials request. Send client_id / client_secret as HTTP Basic auth (RFC 6749 §2.3.1) — do not put them in the body.

curl -X POST https://sandbox.osigu.com/v1/oauth/token \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials"

That's the entire request. No scope parameter is needed — the scopes are pre-configured server-side per client_id and returned in the response.

Response

{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6...",
"token_type": "bearer",
"expires_in": 3600,
"scope": "arc:read arc:write dispensing:read dispensing:write ehr:read ehr:write"
}
  • access_token — the JWT you attach to every subsequent request.
  • token_type — always bearer.
  • expires_in — token lifetime in seconds. Default is 3600 (1 hour).
  • scope — space-delimited scopes the token carries. Depends on your client_id configuration.

Attaching the token

Authorization: Bearer <access_token> on every ARC / Dispensing / EHR call:

curl https://sandbox.osigu.com/arc/v1/authorization-requests/areq_... \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."

Cache aggressively

The token endpoint is rate-limited to 10 requests per minute per client_id. Do not fetch a fresh token per API call.

  • Cache the token in your service (in-memory is fine).
  • Refresh 50 minutes after issuance (leaves 10 minutes of slack for clock skew and slow refresh).
  • Serialise refresh calls — under load, multiple concurrent workers should reuse a single refresh, not stampede the SSO server.

A common pattern:

if cached_token and cached_token.expiry > now + 5min:
return cached_token
with lock:
if cached_token and cached_token.expiry > now + 5min:
return cached_token
cached_token = fetch_new_token()
cached_token.expiry = now + response.expires_in
return cached_token

What the token carries

The JWT payload includes:

  • sub — your client_id.
  • provider_slug — a custom claim identifying which provider this token acts as. This is how the ARC and ePrescription APIs derive the provider without you passing provider_id on every call.
  • scope — the space-delimited scope list.
  • exp / iat — expiration and issued-at.

Osigu's APIs validate the signature against the SSO server's JWKS. Don't try to forge the JWT or edit its claims — signature verification will fail.

Errors

StatusCauseFix
401 UnauthorizedBad client_id / client_secret.Check credentials; note sandbox vs. production credentials are different.
400 Bad Requestinvalid_grantMissing or malformed grant_type.Send grant_type=client_credentials in the body as form-urlencoded.
429 Too Many RequestsYou're refreshing the token too often.Cache.
403 Forbidden on downstream API with a valid tokenToken doesn't carry the scope needed for that endpoint.Contact Osigu support to widen the scope.

Secret rotation

If your client_secret leaks, email security@osigu.com immediately. Osigu can invalidate the old secret and issue a new one in a few minutes. Tokens signed under the old secret continue to work until they expire (max 1 hour), so you have a small overlap window to roll the new secret across your workers.