Authentication
Learn how to authenticate your API requests using API keys, OAuth 2.0, or JWT tokens.
On This Page
API Keys
API keys are the simplest way to authenticate. Include your API key in the
Authorization header of every request.
Getting Your API Key
- Navigate to your API Keys settings
- Click "Create New Key"
- Give your key a descriptive name
- Copy and securely store your key (it won't be shown again)
curl https://api.example.com/v1/users \
-H "Authorization: Bearer YOUR_API_KEY"
API Key Permissions
API keys can be scoped to specific permissions. Available scopes include:
| Scope | Description | Operations |
|---|---|---|
users:read |
Read user data | GET /users, GET /users/:id |
users:write |
Create and update users | POST /users, PUT /users/:id, PATCH /users/:id |
users:delete |
Delete users | DELETE /users/:id |
projects:read |
Read project data | GET /projects, GET /projects/:id |
projects:write |
Create and update projects | POST /projects, PUT /projects/:id |
teams:admin |
Full team management | All team endpoints |
OAuth 2.0
For applications that need to access user data on behalf of users, use OAuth 2.0. We support the authorization code flow with PKCE for maximum security.
OAuth Flow
The OAuth 2.0 flow involves several steps:
-
Register your application
Create an OAuth application in your OAuth Apps settings. You'll receive a client ID and client secret.
-
Redirect users to authorize
let params = new URLSearchParams({ client_id: 'YOUR_CLIENT_ID', redirect_uri: 'https://yourapp.com/callback', response_type: 'code', scope: 'users:read projects:write', state: 'random_state_value' }) window.location.href = `https://api.example.com/oauth/authorize?${params}` -
Handle the callback
After authorization, users are redirected back with an authorization code:
// In your callback handler let code = new URL(window.location.href).searchParams.get('code') // Exchange code for access token let response = await fetch('https://api.example.com/oauth/token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ client_id: 'YOUR_CLIENT_ID', client_secret: 'YOUR_CLIENT_SECRET', code: code, grant_type: 'authorization_code' }) }) let { access_token, refresh_token } = await response.json() -
Use the access token
let response = await fetch('https://api.example.com/v1/users/me', { headers: { 'Authorization': `Bearer ${access_token}` } })
Refreshing Tokens
Access tokens expire after 1 hour. Use refresh tokens to obtain new access tokens:
let response = await fetch('https://api.example.com/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
client_id: 'YOUR_CLIENT_ID',
client_secret: 'YOUR_CLIENT_SECRET',
refresh_token: refresh_token,
grant_type: 'refresh_token'
})
})
let { access_token } = await response.json()
JWT Tokens
For service-to-service authentication, you can use JWT tokens signed with RS256. This is useful for webhook validation and server-side integrations.
Creating a JWT
import jwt from 'jsonwebtoken'
import fs from 'fs'
let privateKey = fs.readFileSync('private-key.pem')
let token = jwt.sign(
{
iss: 'YOUR_CLIENT_ID',
sub: 'user-id',
aud: 'https://api.example.com',
exp: Math.floor(Date.now() / 1000) + 3600
},
privateKey,
{ algorithm: 'RS256' }
)
Verifying a JWT
When you receive a JWT from our API (such as in webhook payloads), verify it using our public key:
import jwt from 'jsonwebtoken'
// Fetch our public key from /.well-known/jwks.json
let publicKey = await fetchPublicKey()
try {
let decoded = jwt.verify(token, publicKey, {
algorithms: ['RS256'],
audience: 'https://yourapp.com',
issuer: 'https://api.example.com'
})
console.log('Valid token:', decoded)
} catch (err) {
console.error('Invalid token:', err)
}
Code Examples
JavaScript/TypeScript
import { ApiClient } from '@example/api-client'
let client = new ApiClient({
apiKey: process.env.API_KEY
})
// List users
let users = await client.users.list({ limit: 10 })
// Create a user
let newUser = await client.users.create({
email: 'user@example.com',
name: 'John Doe'
})
Python
from example_api import ApiClient
client = ApiClient(api_key=os.environ['API_KEY'])
# List users
users = client.users.list(limit=10)
# Create a user
new_user = client.users.create(
email='user@example.com',
name='John Doe'
)
Ruby
require 'example_api'
client = ExampleApi::Client.new(api_key: ENV['API_KEY'])
# List users
users = client.users.list(limit: 10)
# Create a user
new_user = client.users.create(
email: 'user@example.com',
name: 'John Doe'
)
Best Practices
Security Recommendations
- Rotate keys regularly - Set up a rotation schedule for API keys (every 90 days recommended). See key rotation guide.
- Use separate keys per environment - Never use production keys in development. Create environment-specific keys.
- Implement rate limiting - Protect your integration with client-side rate limiting.
- Monitor API usage - Set up alerts for unusual activity in your usage dashboard.
- Use HTTPS only - Never send credentials over unencrypted connections
Error Handling
Authentication errors return specific status codes. See our error reference for details:
| Status Code | Error | Description |
|---|---|---|
| 401 | Unauthorized | Invalid or missing API key |
| 403 | Forbidden | Valid key but insufficient permissions |
| 429 | Rate Limited | Too many requests, see rate limits |