Skip to content

Authentication

Cohera supports multiple authentication methods to fit different integration patterns. Choose the method that best suits your use case.

MethodUse CaseToken Lifetime
API KeyServer-to-server integrationsUntil revoked (max 1 year)
OAuth2 Client CredentialsMachine-to-machine workflows1 hour
JWT BearerUser context required15 minutes

API keys are the simplest way to authenticate. They’re ideal for backend services and scripts.

  1. Navigate to Settings > API Keys in the dashboard
  2. Click Create API Key
  3. Select the required scopes
  4. Set an expiration date
  5. Copy and securely store the key

Include the API key in the Authorization header:

Terminal window
curl -X GET "https://api.cohera.io/v1/entities" \
-H "Authorization: Bearer ck_live_abc123def456..."
PrefixEnvironment
ck_live_Production
ck_test_Sandbox

For machine-to-machine integrations that require scoped access tokens, use OAuth2 client credentials flow.

  1. Navigate to Settings > OAuth Applications
  2. Click Create Application
  3. Note the client_id and client_secret

Exchange your credentials for an access token:

Terminal window
curl -X POST "https://auth.cohera.io/oauth/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "scope=entities:read entities:write"
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "entities:read entities:write"
}
Terminal window
curl -X GET "https://api.cohera.io/v1/entities" \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

JWT tokens contain claims about the authenticated user or service. Understanding token structure helps with debugging.

A Cohera JWT contains:

{
"header": {
"alg": "RS256",
"typ": "JWT",
"kid": "key-123"
},
"payload": {
"iss": "https://auth.cohera.io",
"sub": "user_abc123",
"aud": "https://api.cohera.io",
"exp": 1705312200,
"iat": 1705311300,
"scope": "entities:read entities:write",
"org_id": "org_xyz789"
}
}

Tokens are validated automatically by the API. For advanced use cases, you can validate tokens locally:

import jwt
import requests
# Fetch Cohera's public keys
jwks_response = requests.get("https://auth.cohera.io/.well-known/jwks.json")
jwks = jwks_response.json()
# Validate the token
decoded = jwt.decode(
token,
jwks,
algorithms=["RS256"],
audience="https://api.cohera.io",
issuer="https://auth.cohera.io"
)

OAuth2 tokens expire after 1 hour. Implement token refresh in your application:

import time
class CoheraClient:
def __init__(self, client_id, client_secret):
self.client_id = client_id
self.client_secret = client_secret
self.token = None
self.token_expiry = 0
def get_token(self):
if time.time() >= self.token_expiry - 60: # Refresh 1 min early
self._refresh_token()
return self.token
def _refresh_token(self):
response = requests.post(
"https://auth.cohera.io/oauth/token",
data={
"grant_type": "client_credentials",
"client_id": self.client_id,
"client_secret": self.client_secret,
}
)
data = response.json()
self.token = data["access_token"]
self.token_expiry = time.time() + data["expires_in"]
ScopeDescription
entities:readRead entity data
entities:writeCreate and update entities
entities:deleteDelete entities
certificates:readRead certificate data
certificates:writeUpload and update certificates
suppliers:readRead supplier information
suppliers:writeManage supplier data
quality-events:readRead deviations, CAPAs, audits
quality-events:writeCreate and update quality events
workflows:readRead workflow states
workflows:executeTrigger workflow transitions
audit-logs:readRead audit trail data
admin:readRead organization settings
admin:writeManage organization settings

Cohera implements rate limiting to ensure fair usage and platform stability.

TierRequests/minuteBurst
Free6010
Professional30050
Enterprise1,000100
CustomContact sales-

Every response includes rate limit information:

X-RateLimit-Limit: 300
X-RateLimit-Remaining: 295
X-RateLimit-Reset: 1705312200

When rate limited, you’ll receive a 429 Too Many Requests response:

{
"error": {
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded. Please retry after 30 seconds.",
"retry_after": 30
}
}

Implement exponential backoff in your client:

import time
import requests
def make_request_with_retry(url, headers, max_retries=3):
for attempt in range(max_retries):
response = requests.get(url, headers=headers)
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 30))
time.sleep(retry_after * (2 ** attempt))
continue
return response
raise Exception("Max retries exceeded")

Authentication errors return standard HTTP status codes:

CodeErrorDescription
401unauthorizedMissing or invalid credentials
403forbiddenValid credentials but insufficient permissions
429rate_limit_exceededToo many requests
{
"error": {
"code": "unauthorized",
"message": "Invalid API key provided",
"request_id": "req_abc123"
}
}