---
title: "OAuth 2.0"
description: "Implement OAuth 2.0 authentication for user-facing applications and third-party integrations"
keywords: [oauth, oauth2, authentication, authorization, user consent]
---

# OAuth 2.0

OAuth 2.0 provides secure, user-consent-based authentication for user-facing applications and third-party integrations.

## Overview

OAuth 2.0 enables:
- **User authorization**: Users grant specific permissions
- **Secure delegation**: Applications act on behalf of users
- **Token refresh**: Long-lived access via refresh tokens
- **Granular scopes**: Fine-grained permission control

## OAuth 2.0 Flow

```mermaid
sequenceDiagram
    participant User
    participant App
    participant TraceRTM
    participant API

    User->>App: Request access
    App->>TraceRTM: Redirect to authorization
    TraceRTM->>User: Show consent screen
    User->>TraceRTM: Grant permissions
    TraceRTM->>App: Authorization code
    App->>TraceRTM: Exchange code for tokens
    TraceRTM->>App: Access token + Refresh token
    App->>API: API request with token
    API->>App: Response
```

## Register Your Application

### 1. Create OAuth Application

In the TraceRTM dashboard:

1. Navigate to **Settings** → **OAuth Applications**
2. Click **Create Application**
3. Fill in application details:
   - **Name**: Your application name
   - **Redirect URI**: Where users are redirected after authorization
   - **Scopes**: Requested permissions

### 2. Get Client Credentials

After registration, you'll receive:
- **Client ID**: Public identifier
- **Client Secret**: Keep this secure!

```bash
# Store credentials securely
export TRACERTM_CLIENT_ID="client_abc123..."
export TRACERTM_CLIENT_SECRET="secret_xyz789..."
```

## Authorization Flow

### Step 1: Redirect to Authorization

Direct users to the authorization endpoint:

```
https://api.tracertm.dev/oauth/authorize?
  client_id=client_abc123...
  &redirect_uri=https://yourapp.com/callback
  &response_type=code
  &scope=read write
  &state=random_state_string
```

**Parameters**:
- `client_id`: Your OAuth application client ID
- `redirect_uri`: Must match registered redirect URI
- `response_type`: Always `code` for authorization code flow
- `scope`: Space-separated list of requested scopes
- `state`: Random string for CSRF protection

### Step 2: User Authorization

User sees consent screen and grants permissions.

### Step 3: Receive Authorization Code

User is redirected back with authorization code:

```
https://yourapp.com/callback?
  code=auth_code_123...
  &state=random_state_string
```

### Step 4: Exchange Code for Tokens

Exchange authorization code for access and refresh tokens:

```bash
curl -X POST "https://api.tracertm.dev/oauth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=auth_code_123..." \
  -d "redirect_uri=https://yourapp.com/callback" \
  -d "client_id=client_abc123..." \
  -d "client_secret=secret_xyz789..."
```

**Response**:
```json
{
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "token_type": "bearer",
  "expires_in": 3600,
  "refresh_token": "refresh_token_abc123...",
  "scope": "read write"
}
```

## Using Access Tokens

Include the access token in the `Authorization` header:

```bash
curl -X GET "https://api.tracertm.dev/v1/projects" \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
  -H "Content-Type: application/json"
```

## Refreshing Tokens

Access tokens expire after 1 hour. Use refresh tokens to get new access tokens:

```bash
curl -X POST "https://api.tracertm.dev/oauth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "refresh_token=refresh_token_abc123..." \
  -d "client_id=client_abc123..." \
  -d "client_secret=secret_xyz789..."
```

**Response**:
```json
{
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "token_type": "bearer",
  "expires_in": 3600,
  "refresh_token": "refresh_token_new_xyz789..."
}
```

## Scopes

Scopes define what permissions your application requests:

| Scope | Description |
|-------|-------------|
| `read` | Read access to resources |
| `write` | Create and update resources |
| `delete` | Delete resources |
| `admin` | Administrative access |
| `projects:read` | Read project data |
| `projects:write` | Modify projects |
| `items:read` | Read items |
| `items:write` | Create/update items |

Request multiple scopes:
```
scope=read write projects:read items:write
```

## Implementation Examples

### Python

```python
import requests
from urllib.parse import urlencode

# Step 1: Redirect user to authorization
auth_url = "https://api.tracertm.dev/oauth/authorize"
params = {
    "client_id": "client_abc123...",
    "redirect_uri": "https://yourapp.com/callback",
    "response_type": "code",
    "scope": "read write",
    "state": "random_state_string"
}
authorization_url = f"{auth_url}?{urlencode(params)}"
# Redirect user to authorization_url

# Step 2: Exchange code for tokens (in callback handler)
def handle_callback(auth_code):
    token_url = "https://api.tracertm.dev/oauth/token"
    data = {
        "grant_type": "authorization_code",
        "code": auth_code,
        "redirect_uri": "https://yourapp.com/callback",
        "client_id": "client_abc123...",
        "client_secret": "secret_xyz789..."
    }
    response = requests.post(token_url, data=data)
    tokens = response.json()
    return tokens

# Step 3: Use access token
def make_api_request(access_token):
    headers = {
        "Authorization": f"Bearer {access_token}",
        "Content-Type": "application/json"
    }
    response = requests.get(
        "https://api.tracertm.dev/v1/projects",
        headers=headers
    )
    return response.json()
```

### JavaScript (Node.js)

```javascript
const express = require('express');
const axios = require('axios');
const app = express();

// Step 1: Redirect to authorization
app.get('/auth', (req, res) => {
  const params = new URLSearchParams({
    client_id: process.env.TRACERTM_CLIENT_ID,
    redirect_uri: 'https://yourapp.com/callback',
    response_type: 'code',
    scope: 'read write',
    state: 'random_state_string'
  });
  
  res.redirect(`https://api.tracertm.dev/oauth/authorize?${params}`);
});

// Step 2: Handle callback
app.get('/callback', async (req, res) => {
  const { code } = req.query;
  
  try {
    const response = await axios.post(
      'https://api.tracertm.dev/oauth/token',
      new URLSearchParams({
        grant_type: 'authorization_code',
        code: code,
        redirect_uri: 'https://yourapp.com/callback',
        client_id: process.env.TRACERTM_CLIENT_ID,
        client_secret: process.env.TRACERTM_CLIENT_SECRET
      })
    );
    
    const { access_token, refresh_token } = response.data;
    // Store tokens securely
    // Redirect to app
    res.redirect('/dashboard');
  } catch (error) {
    res.status(500).send('Authentication failed');
  }
});

// Step 3: Refresh token
async function refreshAccessToken(refreshToken) {
  const response = await axios.post(
    'https://api.tracertm.dev/oauth/token',
    new URLSearchParams({
      grant_type: 'refresh_token',
      refresh_token: refreshToken,
      client_id: process.env.TRACERTM_CLIENT_ID,
      client_secret: process.env.TRACERTM_CLIENT_SECRET
    })
  );
  
  return response.data;
}
```

## Security Best Practices

### 1. Protect Client Secret
Never expose client secret in client-side code. Only use in server-side applications.

### 2. Use State Parameter
Always include a random `state` parameter to prevent CSRF attacks:

```python
import secrets

state = secrets.token_urlsafe(32)
# Store in session
# Verify on callback
```

### 3. Validate Redirect URI
Always validate the redirect URI matches your registered URI.

### 4. Store Tokens Securely
- Encrypt tokens at rest
- Use HTTPS for all token exchanges
- Never log tokens

### 5. Handle Token Expiration
Implement automatic token refresh:

```python
def get_valid_token():
    if is_token_expired(access_token):
        tokens = refresh_token(refresh_token)
        access_token = tokens['access_token']
    return access_token
```

## Error Handling

### Invalid Client

```json
{
  "error": "invalid_client",
  "error_description": "Invalid client credentials"
}
```

### Invalid Grant

```json
{
  "error": "invalid_grant",
  "error_description": "Authorization code expired or invalid"
}
```

### Access Denied

```json
{
  "error": "access_denied",
  "error_description": "User denied authorization"
}
```

## Token Expiration

- **Access tokens**: Expire after 1 hour
- **Refresh tokens**: Expire after 90 days (if unused)
- **Authorization codes**: Expire after 10 minutes

## Next Steps

- [JWT Tokens](./04-jwt) - Alternative token-based auth
- [Scopes](./05-scopes) - Understand permission scopes
- [Best Practices](./07-best-practices) - Security guidelines
