Authentication

Authentication tokens are passed using an auth header, and are used to authenticate as a user or organization account with the API. In our documentation, we have several placeholders that appear between curly braces or chevrons, such as {API_KEY} or <auth_token>, which you will need to replace with one of your authentication tokens in order to use the API call effectively.

For example, when the documentation says:

Copied
curl -H 'Authorization: Bearer {TOKEN}' https://sentry.io/api/0/organizations/{organization_slug}/projects/

If your authentication token is 1a2b3c, and your organization slug is acme then the command should be:

Copied
curl -H 'Authorization: Bearer 1a2b3c' https://sentry.io/api/0/organizations/acme/projects/

You can create authentication tokens within Sentry by creating an internal integration. This is also available for self-hosted Sentry.

Some API endpoints require an authentication token that's associated with your user account, rather than an authentication token from an internal integration. These auth tokens can be created within Sentry on the "User settings" page (User settings > Personal Tokens) and assigned specific scopes.

The endpoints that require a user authentication token are specific to your user, such as Retrieve an Organization.

For third-party applications that need to access Sentry on behalf of users, Sentry supports OAuth2 with the authorization code grant type. This allows users to authorize your application without sharing their credentials.

Direct users to the authorization endpoint:

Copied
https://sentry.io/oauth/authorize/?client_id={CLIENT_ID}&response_type=code&scope={SCOPES}

Parameters:

ParameterRequiredDescription
client_idYesYour registered client ID
response_typeYesMust be code
scopeYesSpace-separated list of permissions
redirect_uriNoYour callback URI (must match registered URI)
stateNoRandom string to prevent CSRF attacks
code_challengeRecommendedPKCE challenge (see below)
code_challenge_methodRecommendedMust be S256

After the user approves, Sentry redirects to your callback URI with an authorization code:

Copied
https://your-app.com/callback?code={AUTHORIZATION_CODE}

Exchange the authorization code for an access token:

Copied
curl -X POST https://sentry.io/oauth/token/ \
  -d client_id={CLIENT_ID} \
  -d client_secret={CLIENT_SECRET} \
  -d grant_type=authorization_code \
  -d code={AUTHORIZATION_CODE} \
  -d code_verifier={CODE_VERIFIER}

The code_verifier parameter is required if you used PKCE in the authorization request.

Response:

Copied
{
  "access_token": "{ACCESS_TOKEN}",
  "refresh_token": "{REFRESH_TOKEN}",
  "expires_in": 2591999,
  "expires_at": "2024-11-27T23:20:21.054320Z",
  "token_type": "bearer",
  "scope": "org:read project:read",
  "user": {
    "id": "123",
    "name": "Jane Doe",
    "email": "jane@example.com"
  }
}

Access tokens expire after 30 days. Use the refresh token to obtain new tokens:

Copied
curl -X POST https://sentry.io/oauth/token/ \
  -d client_id={CLIENT_ID} \
  -d client_secret={CLIENT_SECRET} \
  -d grant_type=refresh_token \
  -d refresh_token={REFRESH_TOKEN}

Include the access token in API requests using the Authorization header:

Copied
curl -H 'Authorization: Bearer {ACCESS_TOKEN}' \
  https://sentry.io/api/0/organizations/

A Sentry user can belong to multiple organizations. The access token only provides access to the specific organization the user selected during the OAuth flow. The /api/0/organizations/ endpoint will only return the connected organization.

PKCE protects against authorization code interception attacks and is strongly recommended for all OAuth clients.

How it works: For each authorization request, generate a unique random secret called the code_verifier. Create a code_challenge by hashing this verifier. The challenge is sent with the authorization request, while the original verifier is sent when exchanging the code for a token. Sentry verifies they match, ensuring the same client that started the flow is completing it.

Generating PKCE values (generate fresh for each authorization request):

Copied
import base64
import hashlib
import secrets

# Generate a random code_verifier (43-128 URL-safe characters)
code_verifier = secrets.token_urlsafe(64)

# Create code_challenge by hashing the verifier with SHA256
code_challenge = base64.urlsafe_b64encode(
    hashlib.sha256(code_verifier.encode()).digest()
).rstrip(b'=').decode()

# Store code_verifier securely - you'll need it for the token exchange

Status CodeMeaningAction
401Token expired or revokedRefresh the token, or prompt user to reconnect
403Insufficient permissionsRequest additional scopes or handle gracefully

Copied
import base64
import hashlib
import secrets

import requests
from flask import Flask, redirect, request, session

app = Flask(__name__)
app.secret_key = 'your-secret-key'

CLIENT_ID = 'your-client-id'
CLIENT_SECRET = 'your-client-secret'
REDIRECT_URI = 'https://your-app.com/callback'
TOKEN_URL = 'https://sentry.io/oauth/token/'

def generate_pkce_pair():
    """Generate a code verifier and challenge for PKCE."""
    code_verifier = secrets.token_urlsafe(64)
    code_challenge = base64.urlsafe_b64encode(
        hashlib.sha256(code_verifier.encode()).digest()
    ).rstrip(b'=').decode()
    return code_verifier, code_challenge

@app.route('/connect')
def connect():
    code_verifier, code_challenge = generate_pkce_pair()
    session['code_verifier'] = code_verifier

    return redirect(
        f"https://sentry.io/oauth/authorize/"
        f"?client_id={CLIENT_ID}"
        f"&response_type=code"
        f"&scope=org:read%20project:read"
        f"&redirect_uri={REDIRECT_URI}"
        f"&code_challenge={code_challenge}"
        f"&code_challenge_method=S256"
    )

@app.route('/callback')
def callback():
    code = request.args.get('code')
    code_verifier = session.pop('code_verifier', None)

    response = requests.post(TOKEN_URL, data={
        "client_id": CLIENT_ID,
        "client_secret": CLIENT_SECRET,
        "grant_type": "authorization_code",
        "code": code,
        "code_verifier": code_verifier
    })
    tokens = response.json()

    session['access_token'] = tokens['access_token']
    session['refresh_token'] = tokens['refresh_token']
    return "Connected!"

def refresh_token():
    response = requests.post(TOKEN_URL, data={
        "client_id": CLIENT_ID,
        "client_secret": CLIENT_SECRET,
        "grant_type": "refresh_token",
        "refresh_token": session['refresh_token']
    })
    tokens = response.json()
    session['access_token'] = tokens['access_token']
    session['refresh_token'] = tokens['refresh_token']

Some API endpoints may allow DSN-based authentication. This is generally very limited and an endpoint will describe if its supported. This works similar to Bearer token authentication, but uses your DSN (Client Key).

Copied
curl -H 'Authorization: DSN {DSN}' https://sentry.io/api/0/{organization_slug}/{project_slug}/user-reports/

API keys are passed using HTTP Basic auth where the username is your api key, and the password is an empty value.

As an example, to get information about the project which your key is bound to, you might make a request like so:

Copied
curl -u {API_KEY}: https://sentry.io/api/0/organizations/{organization_slug}/projects/
Was this helpful?