Authentication
Authentication
Section titled “Authentication”Every request to the Overwatch API (except login and registration) must include a valid credential. Overwatch supports two authentication methods: JWT Bearer tokens for user sessions and API keys for service integrations.
JWT Bearer Tokens
Section titled “JWT Bearer Tokens”JWT (JSON Web Token) authentication is designed for interactive user sessions. You exchange a username and password for a short-lived access token, then include that token in subsequent requests.
Obtain a Token
Section titled “Obtain a Token”Send a POST request to the login endpoint with the user’s email and password:
curl -X POST "https://<your-instance>/api/v1/auth/login" \ -H "Content-Type: application/json" \ -d '{ "email": "engineer@example.com", "password": "your-password" }'A successful response returns both an access token and a refresh token:
{ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "bearer", "expires_in": 3600, "user": { "id": "user-uuid", "email": "engineer@example.com", "name": "Jane Doe", "role": "engineer", "organization_id": "org-uuid" }}Note: The login endpoint also sets the access token and refresh token as
httpOnlycookies. Browser-based clients can rely on cookies for automatic credential handling. Non-browser clients should use theaccess_tokenfrom the response body.
Use the Token
Section titled “Use the Token”Include the access token in the Authorization header of every request:
curl -X GET "https://<your-instance>/api/v1/incidents" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."Token Expiry
Section titled “Token Expiry”Access tokens expire after 1 hour (3,600 seconds). The expires_in field in the login response confirms this value. When a token expires, the API returns 401 Unauthorized:
{ "detail": "JWT token has expired"}Refresh a Token
Section titled “Refresh a Token”Use the refresh token to obtain a new access token without re-entering credentials. Refresh tokens are valid for 7 days.
curl -X POST "https://<your-instance>/api/v1/auth/refresh" \ -H "Content-Type: application/json" \ -d '{ "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }'Response:
{ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "bearer", "expires_in": 3600}Tip: Implement proactive refresh logic in your client. Rather than waiting for a
401response, check the token’sexpclaim and refresh the token a few minutes before it expires. This avoids failed requests during the refresh window.
Refresh Strategy
Section titled “Refresh Strategy”A recommended refresh pattern:
- After login, store both the
access_tokenandrefresh_token. - Before each API call, check whether the access token expires within the next 5 minutes.
- If it does, call
/auth/refreshfirst, store the new access token, and then proceed with the original request. - If the refresh token itself has expired or is revoked, redirect the user to the login page.
Logout
Section titled “Logout”Revoking the current session invalidates the access token and clears any session cookies:
curl -X POST "https://<your-instance>/api/v1/auth/logout" \ -H "Authorization: Bearer <access_token>"After logout, the token is added to a revocation list and cannot be reused.
API Keys
Section titled “API Keys”API keys are designed for service-to-service integrations, CI/CD pipelines, and automation scripts. They are long-lived and do not require a refresh flow.
Create an API Key
Section titled “Create an API Key”You must be authenticated with a JWT token (or another API key with sufficient permissions) to create a new key. Specify a descriptive name and the permissions the key should have:
curl -X POST "https://<your-instance>/api/v1/api-keys" \ -H "Authorization: Bearer <access_token>" \ -H "Content-Type: application/json" \ -d '{ "name": "CI/CD Pipeline", "permissions": ["incidents:read", "incidents:create", "procedures:execute"] }'Response:
{ "id": "key-uuid", "name": "CI/CD Pipeline", "api_key": "overwatch_ak_1a2b3c4d5e6f7890", "permissions": ["incidents:read", "incidents:create", "procedures:execute"], "created_at": "2026-02-20T14:30:00Z"}Note: The
api_keyvalue is displayed only once in this response. Store it immediately in a secrets manager or environment variable. It cannot be retrieved again.
Use an API Key
Section titled “Use an API Key”Include the API key in the X-API-Key header:
curl -X GET "https://<your-instance>/api/v1/incidents" \ -H "X-API-Key: overwatch_ak_1a2b3c4d5e6f7890"List API Keys
Section titled “List API Keys”Retrieve all API keys for your organization (the key values themselves are not returned):
curl -X GET "https://<your-instance>/api/v1/api-keys" \ -H "Authorization: Bearer <access_token>"Revoke an API Key
Section titled “Revoke an API Key”Delete an API key immediately. Any request using the revoked key will receive 401 Unauthorized:
curl -X DELETE "https://<your-instance>/api/v1/api-keys/<key_id>" \ -H "Authorization: Bearer <access_token>"Organization Context
Section titled “Organization Context”Both JWT tokens and API keys are scoped to an organization. The organization ID is embedded in the JWT claims (org_id) and associated with the API key at creation time. Every API request is automatically filtered to return only data belonging to that organization.
You do not need to pass an organization_id parameter on requests. The backend derives it from the authenticated credential.
Choosing an Authentication Method
Section titled “Choosing an Authentication Method”| Factor | JWT Bearer Token | API Key |
|---|---|---|
| Best for | User sessions, dashboards, Chrome extension | CI/CD, scripts, webhooks, service integrations |
| Lifetime | 1 hour (access), 7 days (refresh) | Until revoked or expired |
| Credential rotation | Automatic via refresh | Manual (revoke and recreate) |
| Permission scope | Inherited from user role | Explicitly configured per key |
| Supports SSO | Yes | No |
Tip: For automated systems that run unattended, always use API keys. Reserve JWT tokens for interactive sessions where a human is present.
Security Best Practices
Section titled “Security Best Practices”- Store credentials securely. Never commit tokens or API keys to source control. Use environment variables, CI/CD secrets, or a secrets manager.
- Scope API keys narrowly. Grant only the permissions the integration needs. A monitoring webhook that creates incidents does not need
procedures:execute. - Rotate API keys regularly. Set a rotation schedule (every 90 days is a common baseline) and revoke old keys after rotation.
- Monitor usage. Review API key activity in the audit log to detect anomalous patterns.
- Use HTTPS in production. Overwatch enforces HTTPS in production environments. Never transmit tokens over unencrypted HTTP outside of local development.
Error Responses
Section titled “Error Responses”Authentication failures return one of the following:
| Status | Code | Meaning |
|---|---|---|
401 | INVALID_TOKEN | Token is missing, malformed, or expired |
401 | INVALID_API_KEY | API key is not found or has been revoked |
403 | INSUFFICIENT_PERMISSIONS | Credential is valid but lacks the required permission |
423 | ACCOUNT_LOCKED | Too many failed login attempts; account is temporarily locked |
Example:
{ "detail": "JWT token has expired", "status_code": 401}Next Steps
Section titled “Next Steps”- API Examples — Working code samples for authentication and common operations in curl, JavaScript, and Python.
- API Reference — Full endpoint listing with request and response schemas.
- Webhooks — Configuring inbound and outbound webhook integrations.