OAuth 2.0 is an alternative to API keys. Both authentication methods are supported and accept the same
Authorization: Bearer <token> header on every API endpoint. You can keep using API keys — nothing changes for existing integrations.When to use OAuth 2.0
Reach for OAuth 2.0 over API keys when you need any of the following:- Browser-based login for CLI, TUI, or desktop tools — end users sign in through Rootly and consent to scopes instead of copy-pasting a token. See the CLI & TUI quick start.
- Third-party applications that act on behalf of a Rootly user and need scoped, revocable access.
- Unattended automation (CI, internal services, MCP servers) that needs a user-independent token scoped to a specific team and permission set.
- OpenID Connect discovery — MCP clients and SSO-style integrations that expect
.well-known/openid-configurationand a signed ID token.
Managing OAuth applications
Team admins can create, edit, and revoke OAuth applications from Organization Settings → OAuth Applications. Both public and confidential auth-code clients can also self-register at runtime via Dynamic Client Registration — no admin setup required. Only client-credentials (server-to-server) apps must be created by an admin.Endpoints
OAuth endpoints are served fromhttps://rootly.com (the same host users log in to). API calls authenticated with the resulting token still go to https://api.rootly.com.
| Purpose | Method | URL |
|---|---|---|
| Authorization Server Metadata (RFC 8414) | GET | https://rootly.com/.well-known/oauth-authorization-server |
| OpenID Connect Discovery | GET | https://rootly.com/.well-known/openid-configuration |
| JWKS | GET | https://rootly.com/oauth/discovery/keys |
| Authorization | GET | https://rootly.com/oauth/authorize |
| Token | POST | https://rootly.com/oauth/token |
| Token introspection | POST | https://rootly.com/oauth/introspect |
| Token revocation | POST | https://rootly.com/oauth/revoke |
| UserInfo (OIDC) | GET | https://rootly.com/oauth/userinfo |
| Dynamic Client Registration (RFC 7591) | POST | https://rootly.com/oauth/register |
.well-known document — all endpoint URLs, supported scopes, grant types, and signing algorithms are advertised there.
Client types
| Type | Client secret | Grant types | How to create |
|---|---|---|---|
| Public | No (PKCE) | authorization_code | Self-register via /oauth/register, or in the Rootly UI |
| Confidential | Yes | authorization_code, client_credentials | Self-register via /oauth/register, or in the Rootly UI |
S256. Native CLIs, desktop apps, and MCP clients should register as public.
Confidential clients created via Dynamic Client Registration receive a client_secret in the registration response — it is returned once and cannot be retrieved again. Client-credentials apps (no redirect URI, server-to-server only) must be created by a team admin in the UI.
Quick start: CLI & TUI tools
Native CLIs and TUIs follow the native app pattern — self-register at first launch, open the system browser for sign-in, and capture the authorization code on a local loopback port. No client secret, no copy-pasted tokens. The full flow:- Register a public client (once, cached on disk) via Dynamic Client Registration.
- Generate a PKCE pair (
code_verifier+code_challenge). - Start a loopback HTTP listener on an ephemeral port — its URL is the
redirect_uri. - Open the system browser to
https://rootly.com/oauth/authorizewith the PKCE challenge. - Receive the
codeon the loopback listener, then exchange it at/oauth/token. - Persist the access + refresh tokens to a per-user secret store.
TUI tools that can’t open a browser
If the TUI runs over SSH or in a headless container, print the authorize URL and have the user open it on their workstation. Use SSH port forwarding so the loopback redirect still lands on the remote host:http://127.0.0.1:7890/callback as the redirect URI — the browser redirects to the forwarded port, and the TUI captures the code locally.
Token lifecycle in CLIs
- Access tokens last 1 hour. Refresh proactively on
401or when expiry is <5 min away. - Refresh tokens rotate on use — overwrite the cached refresh token after every refresh.
- On logout, call
POST /oauth/revokewith the refresh token and clear the keychain entry.
Scopes
Scopes are domain-prefixed and combine with your Rootly role to form a permission ceiling — effective permissions = user RBAC ∩ granted scopes. Granting a scope never elevates a user beyond what their role already allows.OIDC scopes
| Scope | Purpose |
|---|---|
openid | Required for OIDC flows; enables id_token issuance. |
profile | Adds name, team_id, role, on_call_role to claims. |
email | Adds email to claims. |
Meta scopes
| Scope | Grants |
|---|---|
all | Full read/write across every Incident Response and On-Call resource. |
ir.all | Full read/write across every Incident Response resource. |
oc.all | Full read/write across every On-Call resource. |
Incident Response (ir.*)
Each resource exposes :read and :write. For example, ir.incidents:read or ir.services:write.
incidents, services, environments, functionalities, severities, incident_types, incident_roles, workflows, catalogs, groups, playbooks, retrospectives, status_pages, form_fields, pulses
On-Call (oc.*)
Each resource exposes :read and :write. For example, oc.alerts:read or oc.schedules:write.
alerts, schedules, escalation_policies, alert_routing_rules, heartbeats, alert_sources, live_call_routing, shift_overrides
Authorization Code flow (with PKCE)
Use this flow for end-user sign-in. Required for public clients, recommended for confidential clients.1. Register the client
Either call the Dynamic Client Registration endpoint (see below) or have a team admin create the application in Organization Settings → OAuth Applications.2. Redirect the user to /oauth/authorize
3. Exchange the code for tokens
Authorization codes are single-use and expire after 60 seconds — exchange them immediately. Public client (PKCE, no secret):4. Call the Rootly API
5. Refresh the token
Access tokens expire after 1 hour. Refresh tokens rotate on use — the old refresh token is invalidated after a short grace period. Public client:Client Credentials flow
Use this flow for server-to-server automation where no end user is involved (CI jobs, scheduled tasks, internal services). Requires a confidential application created by a team admin. When the application is created, Rootly auto-provisions a dedicated service user in the team. The service user’sRole and OnCallRole permissions are derived from the app’s scopes, so the token’s effective access is exactly what the scopes describe.
ir.* or oc.*).
Dynamic Client Registration (RFC 7591)
CLIs, desktop apps, MCP clients, and third-party integrations can self-register without authentication. Both public and confidential auth-code clients are supported. Public client (no secret — typical for CLIs and native apps):client_secret field — store it immediately, as it cannot be retrieved again.
Rules:
token_endpoint_auth_methodmust be one of:none,client_secret_post, orclient_secret_basic.- Redirect URIs must use HTTPS. HTTP is allowed for the loopback addresses
127.0.0.1,[::1], andlocalhostfor local development. - If no
scopeis provided, the app is registered with all available granular scopes so the user can narrow access on the consent screen. - Meta scopes (
all,ir.all,oc.all) are not accepted during registration — use individualir.*andoc.*scopes instead. - Registration is rate-limited to 10 requests per hour per IP.
- The team the application operates against is assigned when the first user authorizes it.
UserInfo
| Claim | Requires scope | Description |
|---|---|---|
sub | openid | Rootly user ID. |
email | email | User email. |
name | profile | User full name. |
team_id | profile | Team the token is scoped to. |
role | profile | Incident Response role name on that team. |
on_call_role | profile | On-Call role name on that team. |
https://rootly.com/oauth/discovery/keys.
Authenticating API calls
On Rootly’s resource API (https://api.rootly.com/v1/*), OAuth 2.0 access tokens and API keys use the same Authorization: Bearer … header. The API tries API keys first, then OAuth tokens — you never need to tell Rootly which one you are sending.
/v1/*. The OAuth protocol endpoints on rootly.com (/oauth/token, /oauth/authorize, /oauth/register, /.well-known/*) use their own authentication rules described above.
Rate limits, pagination, and the JSON:API contract are identical to the API-key path — see the API Overview.
Using Rootly tokens with external services
Rootly’s OAuth 2.0 + OIDC server isn’t only for authenticating to Rootly’s API. Any external service that supports OAuth 2.0 token validation can accept Rootly-issued tokens and use Rootly’s UserInfo response as the source of truth for user identity, team scope, and role. The pattern:- Your application obtains a Rootly OAuth token using one of the flows above.
- The application sends the token as
Authorization: Bearer <ACCESS_TOKEN>to the external service. - The external service validates the token by calling
https://rootly.com/oauth/userinfowith that sameAuthorizationheader, then reads the returned claims (sub,team_id,role,on_call_role) for access decisions.
Example: LiteLLM AI gateway
LiteLLM is an AI gateway proxy that supports OAuth 2.0 token validation as an Enterprise feature. Pointing it at Rootly’s UserInfo endpoint lets your team reuse Rootly identities — and the existing Rootly role and team model — for AI-gateway access control, cost attribution, and rate limiting.Configure LiteLLM to validate against Rootly
Set LiteLLM’s environment variables to point at Rootly’s UserInfo endpoint and the matching claim names:Then enable OAuth 2.0 auth in LiteLLM’s
config.yaml:Issue tokens with the right scopes
LiteLLM reads The token itself does not need any
sub, team_id, and role from Rootly’s UserInfo response. Those claims require the openid and profile scopes to be granted on the access token — see OIDC scopes. A typical scope set for gateway use:ir.* or oc.* resource scopes because the request never touches Rootly’s resource API — only the UserInfo endpoint, which any valid token can call.Call the gateway with a Rootly token
Application code obtains a Rootly access token using whichever flow fits the deployment model:LiteLLM calls Rootly’s UserInfo endpoint with the same bearer token, extracts the user identity and team, and applies whatever per-user or per-team policies you’ve configured in LiteLLM (rate limits, allowed models, spend caps).
- Interactive users — Authorization Code with PKCE (above)
- Server-to-server automation — Client Credentials (above)
Why this is useful
| Outcome | How Rootly OAuth makes it work |
|---|---|
| One identity surface | A user added to Rootly automatically has gateway access; removal revokes both in lockstep. |
| Per-team cost attribution | LiteLLM’s spend tracking groups by team_id from the UserInfo response — same team_id Rootly already scopes incidents and on-call schedules to. |
| Central revocation | Revoke a Rootly OAuth token via POST /oauth/revoke and the gateway stops honoring it immediately. |
| No per-gateway credential sprawl | The gateway never holds long-lived API keys for individual users; it only validates short-lived OAuth tokens at request time. |
LiteLLM’s OAuth 2.0 token validation is a paid Enterprise feature. The Rootly-side OAuth 2.0 server is the same one documented above and is included in standard Rootly access — no additional plan tier is required on Rootly’s side to use Rootly as the identity provider for an external service.