Skip to content

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 (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.

Send a POST request to the login endpoint with the user’s email and password:

Terminal window
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 httpOnly cookies. Browser-based clients can rely on cookies for automatic credential handling. Non-browser clients should use the access_token from the response body.

Include the access token in the Authorization header of every request:

Terminal window
curl -X GET "https://<your-instance>/api/v1/incidents" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

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"
}

Use the refresh token to obtain a new access token without re-entering credentials. Refresh tokens are valid for 7 days.

Terminal window
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 401 response, check the token’s exp claim and refresh the token a few minutes before it expires. This avoids failed requests during the refresh window.

A recommended refresh pattern:

  1. After login, store both the access_token and refresh_token.
  2. Before each API call, check whether the access token expires within the next 5 minutes.
  3. If it does, call /auth/refresh first, store the new access token, and then proceed with the original request.
  4. If the refresh token itself has expired or is revoked, redirect the user to the login page.

Revoking the current session invalidates the access token and clears any session cookies:

Terminal window
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 are designed for service-to-service integrations, CI/CD pipelines, and automation scripts. They are long-lived and do not require a refresh flow.

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:

Terminal window
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_key value is displayed only once in this response. Store it immediately in a secrets manager or environment variable. It cannot be retrieved again.

Include the API key in the X-API-Key header:

Terminal window
curl -X GET "https://<your-instance>/api/v1/incidents" \
-H "X-API-Key: overwatch_ak_1a2b3c4d5e6f7890"

Retrieve all API keys for your organization (the key values themselves are not returned):

Terminal window
curl -X GET "https://<your-instance>/api/v1/api-keys" \
-H "Authorization: Bearer <access_token>"

Delete an API key immediately. Any request using the revoked key will receive 401 Unauthorized:

Terminal window
curl -X DELETE "https://<your-instance>/api/v1/api-keys/<key_id>" \
-H "Authorization: Bearer <access_token>"

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.


FactorJWT Bearer TokenAPI Key
Best forUser sessions, dashboards, Chrome extensionCI/CD, scripts, webhooks, service integrations
Lifetime1 hour (access), 7 days (refresh)Until revoked or expired
Credential rotationAutomatic via refreshManual (revoke and recreate)
Permission scopeInherited from user roleExplicitly configured per key
Supports SSOYesNo

Tip: For automated systems that run unattended, always use API keys. Reserve JWT tokens for interactive sessions where a human is present.


  1. Store credentials securely. Never commit tokens or API keys to source control. Use environment variables, CI/CD secrets, or a secrets manager.
  2. Scope API keys narrowly. Grant only the permissions the integration needs. A monitoring webhook that creates incidents does not need procedures:execute.
  3. Rotate API keys regularly. Set a rotation schedule (every 90 days is a common baseline) and revoke old keys after rotation.
  4. Monitor usage. Review API key activity in the audit log to detect anomalous patterns.
  5. Use HTTPS in production. Overwatch enforces HTTPS in production environments. Never transmit tokens over unencrypted HTTP outside of local development.

Authentication failures return one of the following:

StatusCodeMeaning
401INVALID_TOKENToken is missing, malformed, or expired
401INVALID_API_KEYAPI key is not found or has been revoked
403INSUFFICIENT_PERMISSIONSCredential is valid but lacks the required permission
423ACCOUNT_LOCKEDToo many failed login attempts; account is temporarily locked

Example:

{
"detail": "JWT token has expired",
"status_code": 401
}

  • 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.