Authentication
Cohera supports multiple authentication methods to fit different integration patterns. Choose the method that best suits your use case.
Authentication Methods
Section titled “Authentication Methods”| Method | Use Case | Token Lifetime |
|---|---|---|
| API Key | Server-to-server integrations | Until revoked (max 1 year) |
| OAuth2 Client Credentials | Machine-to-machine workflows | 1 hour |
| JWT Bearer | User context required | 15 minutes |
API Key Authentication
Section titled “API Key Authentication”API keys are the simplest way to authenticate. They’re ideal for backend services and scripts.
Generating an API Key
Section titled “Generating an API Key”- Navigate to Settings > API Keys in the dashboard
- Click Create API Key
- Select the required scopes
- Set an expiration date
- Copy and securely store the key
Using an API Key
Section titled “Using an API Key”Include the API key in the Authorization header:
curl -X GET "https://api.cohera.io/v1/entities" \ -H "Authorization: Bearer ck_live_abc123def456..."import requests
headers = { "Authorization": "Bearer ck_live_abc123def456...", "Content-Type": "application/json"}
response = requests.get( "https://api.cohera.io/v1/entities", headers=headers)const response = await fetch("https://api.cohera.io/v1/entities", { headers: { "Authorization": "Bearer ck_live_abc123def456...", "Content-Type": "application/json", },});API Key Prefixes
Section titled “API Key Prefixes”| Prefix | Environment |
|---|---|
ck_live_ | Production |
ck_test_ | Sandbox |
OAuth2 Client Credentials
Section titled “OAuth2 Client Credentials”For machine-to-machine integrations that require scoped access tokens, use OAuth2 client credentials flow.
Obtaining Client Credentials
Section titled “Obtaining Client Credentials”- Navigate to Settings > OAuth Applications
- Click Create Application
- Note the
client_idandclient_secret
Token Request
Section titled “Token Request”Exchange your credentials for an access token:
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"import requests
response = requests.post( "https://auth.cohera.io/oauth/token", data={ "grant_type": "client_credentials", "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET", "scope": "entities:read entities:write" })
token = response.json()["access_token"]const response = await fetch("https://auth.cohera.io/oauth/token", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", }, body: new URLSearchParams({ grant_type: "client_credentials", client_id: "YOUR_CLIENT_ID", client_secret: "YOUR_CLIENT_SECRET", scope: "entities:read entities:write", }),});
const { access_token } = await response.json();Token Response
Section titled “Token Response”{ "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "Bearer", "expires_in": 3600, "scope": "entities:read entities:write"}Using the Token
Section titled “Using the Token”curl -X GET "https://api.cohera.io/v1/entities" \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."JWT Token Handling
Section titled “JWT Token Handling”JWT tokens contain claims about the authenticated user or service. Understanding token structure helps with debugging.
Token Structure
Section titled “Token Structure”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" }}Validating Tokens
Section titled “Validating Tokens”Tokens are validated automatically by the API. For advanced use cases, you can validate tokens locally:
import jwtimport requests
# Fetch Cohera's public keysjwks_response = requests.get("https://auth.cohera.io/.well-known/jwks.json")jwks = jwks_response.json()
# Validate the tokendecoded = jwt.decode( token, jwks, algorithms=["RS256"], audience="https://api.cohera.io", issuer="https://auth.cohera.io")Token Refresh
Section titled “Token Refresh”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"]Available Scopes
Section titled “Available Scopes”| Scope | Description |
|---|---|
entities:read | Read entity data |
entities:write | Create and update entities |
entities:delete | Delete entities |
certificates:read | Read certificate data |
certificates:write | Upload and update certificates |
suppliers:read | Read supplier information |
suppliers:write | Manage supplier data |
quality-events:read | Read deviations, CAPAs, audits |
quality-events:write | Create and update quality events |
workflows:read | Read workflow states |
workflows:execute | Trigger workflow transitions |
audit-logs:read | Read audit trail data |
admin:read | Read organization settings |
admin:write | Manage organization settings |
Rate Limits
Section titled “Rate Limits”Cohera implements rate limiting to ensure fair usage and platform stability.
Default Limits
Section titled “Default Limits”| Tier | Requests/minute | Burst |
|---|---|---|
| Free | 60 | 10 |
| Professional | 300 | 50 |
| Enterprise | 1,000 | 100 |
| Custom | Contact sales | - |
Rate Limit Headers
Section titled “Rate Limit Headers”Every response includes rate limit information:
X-RateLimit-Limit: 300X-RateLimit-Remaining: 295X-RateLimit-Reset: 1705312200Handling Rate Limits
Section titled “Handling Rate Limits”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 timeimport 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")Error Responses
Section titled “Error Responses”Authentication errors return standard HTTP status codes:
| Code | Error | Description |
|---|---|---|
| 401 | unauthorized | Missing or invalid credentials |
| 403 | forbidden | Valid credentials but insufficient permissions |
| 429 | rate_limit_exceeded | Too many requests |
{ "error": { "code": "unauthorized", "message": "Invalid API key provided", "request_id": "req_abc123" }}Next Steps
Section titled “Next Steps”- Entities API - Start working with entity data
- API Reference - Complete API documentation
- Integrations - Connect to enterprise systems