> ## Documentation Index
> Fetch the complete documentation index at: https://docs.deploystack.io/llms.txt
> Use this file to discover all available pages before exploring further.

# OAuth2 Server Implementation

> Developer guide for the OAuth2 authorization server that enables programmatic API access via Bearer tokens

<Note>
  **OAuth System Clarification**: DeployStack implements three distinct OAuth systems:

  1. **User → DeployStack OAuth** (Social Login) - See [OAuth Providers](/development/backend/oauth-providers)
  2. **MCP Client → DeployStack OAuth** (API Access) - **This document** - How VS Code, Cursor, Claude.ai authenticate to satellite APIs
  3. **User → MCP Server OAuth** (External Service Access) - See [MCP Server OAuth](/development/backend/mcp-server-oauth) - How users authorize Notion, Box, Linear

  This document covers system #2 - the OAuth2 authorization server for MCP client authentication.
</Note>

This document describes the OAuth2 authorization server implementation in the DeployStack backend, which enables CLI tools and applications to access APIs using Bearer tokens. For general authentication, see [Backend Authentication System](/development/backend/auth).

## Overview

The OAuth2 server provides RFC 6749 compliant authorization for programmatic API access with RFC 7591 Dynamic Client Registration support. This enables the DeployStack Satellite, MCP clients (VS Code, Cursor, Claude.ai), and other tools to authenticate users and access APIs on their behalf using Bearer tokens instead of cookies.

## Architecture

The OAuth2 server implementation includes:

* **Authorization Server** - Handles OAuth2 authorization flow with PKCE
* **Dynamic Client Registration** - RFC 7591 compliant client registration for MCP clients
* **Token Management** - Issues and validates access/refresh tokens
* **Consent System** - User authorization interface
* **Dual Authentication** - Supports both cookies and Bearer tokens
* **Scope-based Access** - Fine-grained permission control
* **Database Storage** - Persistent client and token storage

## OAuth2 Flow

### Authorization Code Flow with PKCE

The implementation follows the OAuth2 Authorization Code flow enhanced with PKCE (Proof Key for Code Exchange) for additional security:

1. **Client generates PKCE challenge** - Creates code verifier and SHA256 challenge
2. **Authorization request** - Client redirects to `/api/oauth2/auth`
3. **User consent** - User approves requested scopes
4. **Authorization code** - Server returns code to callback
5. **Token exchange** - Client exchanges code for tokens
6. **API access** - Client uses Bearer token for requests

### Dynamic Client Registration Flow (RFC 7591)

MCP clients can automatically register themselves:

1. **Client registration** - POST to `/api/oauth2/register` with metadata
2. **Client validation** - Server validates redirect URIs and grants
3. **Client ID generation** - Server generates unique client\_id (format: `dyn_<timestamp>_<random>`)
4. **Database storage** - Client metadata stored in `dynamic_oauth_clients` table
5. **OAuth flow** - Client proceeds with standard authorization flow

### PKCE Implementation

PKCE provides security for public clients (like CLI tools and MCP clients):

#### Code Verifier

* 128 random bytes encoded as base64url
* Generated by client, kept secret
* Used during token exchange

#### Code Challenge

* SHA256 hash of verifier
* Sent with authorization request
* Stored with authorization code

#### Validation

* Server verifies challenge matches verifier
* Prevents code interception attacks
* Required for all authorization requests

## Service Architecture

### AuthorizationService

Manages the authorization flow:

#### Client Validation

* Validates dynamic clients against database (`dynamic_oauth_clients` table)
* Supports both pre-registered and dynamically registered clients
* Extensible for additional client types

#### Redirect URI Validation

* Checks URI against allowed patterns for MCP clients
* Supports localhost callbacks for CLI tools
* Supports VS Code specific patterns (`http://127.0.0.1:<port>/`, `vscode://`)
* Supports Cursor patterns (`cursor://`)
* Supports Claude.ai patterns (`https://claude.ai/mcp/auth/callback`)
* Prevents redirect attacks

#### Scope Validation

* Validates requested scopes against MCP scope patterns
* Supports `mcp:read`, `mcp:tools:execute`, `offline_access`
* Ensures scopes are recognized
* Limits access appropriately

#### Authorization Storage

* Stores authorization requests in database
* Links PKCE challenges
* Manages request lifecycle with expiration
* Supports team-scoped authorization

#### Code Generation

* Creates authorization codes
* Associates with user session and team
* Implements 10-minute expiration
* Prevents replay attacks

#### Code Verification

* Validates authorization codes against database
* Verifies PKCE challenge
* Ensures single use
* Validates client and redirect URI match

#### Resource Indicators (RFC 8707)

* Accepts optional `resource` parameter in authorization requests
* Stores resource identifier with authorization code
* Returns resource with verification result
* Enables audience binding for tokens

**Purpose:** RFC 8707 Resource Indicators bind tokens to specific resources (e.g., specific MCP satellite URLs) to prevent token reuse across different services.

**Flow:**

1. Client sends `resource` parameter (e.g., `https://satellite.deploystack.io/mcp`)
2. Backend stores resource with authorization code
3. Token generation includes resource in `aud` (audience) claim
4. Satellite validates token audience matches its URL
5. Prevents token stolen from one satellite being used on another

**Database Schema:**

* `oauth_authorization_codes.resource` - TEXT column (nullable)
* Backward compatible - existing codes without resource still work

### Dynamic Client Registration

Implements RFC 7591 Dynamic Client Registration:

#### Registration Endpoint

* **File**: `services/backend/src/routes/oauth2/register.ts`
* **Endpoint**: `POST /api/oauth2/register`
* **Purpose**: Allows MCP clients to self-register

#### Client Metadata Validation

* Validates `redirect_uris` against MCP client patterns
* Supports VS Code: `http://127.0.0.1:<port>/`, `https://vscode.dev/redirect`
* Supports Cursor: `cursor://` schemes
* Supports Claude.ai: `https://claude.ai/mcp/auth/callback`
* Validates `grant_types` (authorization\_code, refresh\_token)
* Validates `response_types` (code)

#### Client ID Generation

* Format: `dyn_<timestamp>_<random>`
* Timestamp: Unix timestamp for uniqueness
* Random suffix: 9-character base36 string
* Example: `dyn_1757880447836_uvze3d0yc`

#### Database Storage

* **Table**: `dynamic_oauth_clients`
* **Schema**: See `services/backend/src/db/schema.ts`
* **Fields**: client\_id, client\_name, redirect\_uris, grant\_types, response\_types, scope, token\_endpoint\_auth\_method, client\_id\_issued\_at, expires\_at
* **Persistence**: Survives server restarts and supports multiple instances

### TokenService

Handles token lifecycle:

#### Token Generation

* Creates cryptographically secure tokens
* Generates appropriate expiration
* Stores hashed versions in database

#### Access Token Management

* Issues 1-week access tokens for MCP clients
* Issues 1-hour access tokens for CLI tools
* Includes user, team, and scope data
* Includes `aud` (audience) claim from resource parameter (RFC 8707)
* Enables API authentication

**Audience Claim Generation:**

* If `resource` parameter provided: `aud` = `[resource]` (e.g., `["https://satellite.deploystack.io/mcp"]`)
* If no resource: `aud` = `["deploystack:team:{teamId}"]` (backward compatibility)
* Token payload includes `aud` field for satellite validation

#### Refresh Token Handling

* Issues 30-day refresh tokens
* Allows token renewal
* Maintains session continuity
* Supports offline access

#### Token Verification

* Validates token format
* Checks expiration
* Verifies against database
* Supports introspection endpoint
* Returns `aud` (audience) claim in introspection response (RFC 7662 + RFC 8707)

**Introspection Response with Audience:**

```json theme={null}
{
  "active": true,
  "scope": "mcp:read mcp:tools:execute",
  "client_id": "vscode_mcp_extension",
  "username": "user@example.com",
  "sub": "user_id",
  "aud": ["https://satellite.deploystack.io/mcp"],
  "iss": "https://cloud.deploystack.io",
  "team_id": "team_xyz",
  "team_name": "Acme Corp"
}
```

Satellites use the `aud` claim to validate tokens are intended for them.

#### Token Refresh

* Exchanges refresh for access token
* Validates client identity
* Maintains scope consistency
* Supports both static and dynamic clients

#### Token Revocation

* Invalidates tokens on demand
* Cleans up related tokens
* Ensures immediate effect

### Database Schema

#### Dynamic OAuth Clients Table

* **File**: `services/backend/src/db/schema.ts`
* **Table**: `dynamic_oauth_clients`
* **Migration**: `0006_keen_firestar.sql`
* **Purpose**: Persistent storage for dynamically registered MCP clients

#### OAuth Authorization Codes Table

* **Table**: `oauth_authorization_codes`
* **Purpose**: Stores authorization requests and codes
* **Features**: PKCE challenge storage, team context, expiration

#### OAuth Access Tokens Table

* **Table**: `oauth_access_tokens`
* **Purpose**: Stores issued access tokens
* **Features**: Hashed storage, scope tracking, team context

#### OAuth Refresh Tokens Table

* **Table**: `oauth_refresh_tokens`
* **Purpose**: Stores refresh tokens for token renewal
* **Features**: Long-term storage, client association

### OAuthCleanupService (TODO)

Automatic maintenance system needs implementation:

#### Scheduled Cleanup

* Should run hourly via cron
* Remove expired authorization codes (>10 minutes)
* Remove expired access tokens
* Remove expired refresh tokens
* Clean up unused dynamic client registrations

#### Cleanup Scope

* Authorization codes > 10 minutes old
* Expired access tokens
* Expired refresh tokens
* Dynamic clients unused for >90 days (configurable)

## OAuth2 Endpoints Overview

The OAuth2 server implements standard OAuth2 endpoints following RFC 6749 and RFC 7591:

### Authorization Flow Endpoints

* **Authorization Endpoint** (`/api/oauth2/auth`) - Initiates the OAuth2 flow with PKCE parameters
* **Consent Endpoints** (`/api/oauth2/consent`) - Displays and processes user authorization consent
* **Token Endpoint** (`/api/oauth2/token`) - Exchanges authorization codes for access tokens and handles token refresh
* **User Info Endpoint** (`/api/oauth2/userinfo`) - Returns authenticated user information
* **Introspection Endpoint** (`/api/oauth2/introspect`) - Token validation for resource servers

### Dynamic Client Registration Endpoints

* **Registration Endpoint** (`/api/oauth2/register`) - RFC 7591 compliant client registration

For complete API specifications including request parameters, response schemas, and examples, see the [Backend API Documentation](/development/backend/api/). The API documentation provides OpenAPI specifications for all OAuth2 endpoints.

## OAuth2 Scopes

### Available Scopes

**MCP Client Scopes:**

* `mcp:read` - Tool discovery and MCP server access
* `mcp:tools:execute` - Tool execution permissions
* `offline_access` - Refresh token issuance

**CLI Tool Scopes:**
For the current list of CLI-supported scopes, see the source code at `services/backend/src/services/oauth/authorizationService.ts` in the `validateScope()` method.

### Default Scopes

The `scope` parameter is **optional** in authorization requests. When not provided, the server defaults to all MCP scopes:

```
mcp:read mcp:tools:execute offline_access
```

This allows MCP clients that don't send the `scope` parameter (like Claude Code) to authenticate without errors.

### Resource Indicators (RFC 8707)

The authorization endpoint supports the optional `resource` parameter for audience binding:

```
GET /api/oauth2/auth?...&resource=https://satellite.deploystack.io/
```

This parameter identifies the target MCP server (satellite) and can be used for token audience validation.

### Scope Enforcement

Scopes are enforced at the endpoint level:

#### Middleware Integration

* `requireOAuthScope()` - Single scope requirement
* `requireAnyOAuthScope()` - Multiple scope options
* Skip enforcement for cookie auth

#### Scope Checking

* Validates token contains required scope
* Returns 403 for insufficient scope
* Provides clear error messages

## Client Types and Configuration

### Dynamic Clients (RFC 7591)

**VS Code MCP Extension:**

* **Client ID**: Auto-generated (e.g., `dyn_1757880447836_uvze3d0yc`)
* **Registration**: Automatic via RFC 7591
* **Redirect URIs**: `http://127.0.0.1:<port>/`, `https://vscode.dev/redirect`
* **Scopes**: `mcp:read mcp:tools:execute offline_access`
* **Token Lifetime**: 1-week access, 30-day refresh

**Cursor MCP Client:**

* **Client ID**: Auto-generated
* **Registration**: Automatic via RFC 7591
* **Redirect URIs**: `cursor://` schemes
* **Scopes**: `mcp:read mcp:tools:execute offline_access`

**Claude.ai MCP Client:**

* **Client ID**: Auto-generated
* **Registration**: Automatic via RFC 7591
* **Redirect URIs**: `https://claude.ai/mcp/auth/callback`
* **Scopes**: `mcp:read mcp:tools:execute offline_access`

### Adding New Static Clients

To support additional pre-registered OAuth2 clients:

1. Add client\_id to validation whitelist in `AuthorizationService.validateClient()`
2. Configure allowed redirect URIs in `AuthorizationService.validateRedirectUri()`
3. Define client-specific settings
4. Update documentation

## Dual Authentication

### Supporting Both Methods

Endpoints can accept cookies or Bearer tokens:

#### Middleware: `requireAuthenticationAny()`

1. First checks cookie session (from authHook)
2. Falls back to Bearer token validation
3. Populates unified `request.user`
4. Maintains authentication type context

#### Implementation Pattern

Routes support both authentication methods:

* Define both security schemes in OpenAPI
* Use dual authentication middleware
* Apply scope requirements conditionally
* Handle both response formats

### Authentication Context

The system maintains context about authentication:

* **Cookie Auth**: `request.user` and `request.session`
* **OAuth2 Auth**: `request.user` and `request.tokenPayload`
* **Type Detection**: Check for `tokenPayload` presence
* **Unified Interface**: Same user object structure

## Security Implementation

### PKCE Security

Protection against authorization code interception:

* Required for all authorization requests
* SHA256 challenge method only
* Cryptographically secure verifier generation
* Single-use authorization codes

### Token Security

Multiple layers of token protection:

* Argon2 hashing for stored tokens
* Constant-time comparison
* Secure random generation
* Automatic expiration
* Regular cleanup (TODO: implement)

### Authorization Security

Secure authorization flow:

* CSRF protection via state parameter
* Proper URL encoding of state parameter
* Session requirement for authorization
* Validated redirect URIs
* Clear consent interface

### Bearer Token Security

API access security:

* Standard Authorization header
* Token validation on each request
* Scope-based access control
* Automatic token refresh

### Dynamic Client Security

RFC 7591 security measures:

* Redirect URI validation against MCP patterns
* Client metadata validation
* Automatic client ID generation
* Database persistence with proper indexing
* No client secrets for public clients

## Integration Examples

### MCP Client Registration Flow

Example dynamic client registration for MCP clients:

1. **Client registration request**
2. **Server validates metadata**
3. **Client ID generated and stored**
4. **Client proceeds with OAuth flow**
5. **User authorizes in browser**
6. **Tokens issued for MCP access**

### CLI Authentication Flow

Example OAuth2 flow for CLI tools:

1. **Generate PKCE challenge**
2. **Open browser for authorization**
3. **Start callback server**
4. **User approves in browser**
5. **Receive authorization code**
6. **Exchange for tokens**
7. **Store tokens securely**
8. **Use Bearer token for API**

### API Request Example

Using Bearer token for API access:

```
GET /api/teams/me/default
Authorization: Bearer <access_token>
```

### Token Refresh Example

Refreshing expired access token:

```
POST /api/oauth2/token
Content-Type: application/json

{
  "grant_type": "refresh_token",
  "refresh_token": "<refresh_token>",
  "client_id": "dyn_1757880447836_uvze3d0yc"
}
```

## Monitoring

### Metrics to Track (TODO)

* Authorization requests
* Dynamic client registrations
* Token issuance rate
* Refresh token usage
* Failed authentication attempts
* Cleanup effectiveness

### Logging (TODO)

Comprehensive logging for debugging:

* Authorization flow steps
* Dynamic client registration events
* Token operations
* Scope validations
* Error conditions
* Security events

## OAuth Scope Management

The backend validates OAuth scopes to control API access. Scope configuration must stay synchronized between the backend and clients.

### Current Scopes

For the current list of supported scopes, check the source code at:

* **Backend validation**: `services/backend/src/services/oauth/authorizationService.ts` in the `validateScope()` method

### Adding New Scopes

When adding support for a new OAuth scope in the backend:

1. **Add the scope** to the `allowedScopes` array in `services/backend/src/services/oauth/authorizationService.ts`
2. **Update clients** to request the new scope (Satellite, MCP clients)
3. **Apply scope enforcement** to relevant API endpoints using middleware
4. **Test the complete flow** to ensure proper scope validation

Example:

```typescript theme={null}
// In services/backend/src/services/oauth/authorizationService.ts
static validateScope(scope: string): boolean {
  const requestedScopes = scope.split(' ');
  const allowedScopes = [
    'mcp:read',
    'mcp:tools:execute',
    'offline_access',
    'your-new-scope',  // Add new scope here
    // ... other scopes
  ];
  
  return requestedScopes.every(s => allowedScopes.includes(s));
}
```

### Scope Enforcement in Routes

Apply scope requirements to API endpoints:

```typescript theme={null}
// Single scope requirement
server.get('/api/your-endpoint', {
  preValidation: [
    requireValidAccessToken(),
    requireOAuthScope('your-new-scope')
  ]
}, async (request, reply) => {
  // Your endpoint logic
});

// Multiple scope options
server.get('/api/another-endpoint', {
  preValidation: [
    requireValidAccessToken(),
    requireAnyOAuthScope(['scope1', 'scope2'])
  ]
}, async (request, reply) => {
  // Your endpoint logic
});
```

### Scope Synchronization

**Critical**: The backend and clients must have matching scope configurations:

* If backend supports a scope but client doesn't request it, users won't get that permission
* If client requests a scope but backend doesn't support it, authentication will fail

Always coordinate scope changes between backend and client implementations.

## MCP Client Integration

The OAuth2 server supports MCP clients through dynamic registration:

### Supported MCP Clients

* **VS Code MCP Extension** - Automatic registration and authentication
* **Cursor MCP Client** - Dynamic client registration support
* **Claude.ai Custom Connector** - OAuth2 integration
* **Cline MCP Client** - VS Code extension support

### MCP Client Flow

1. **Dynamic Registration** - Client registers via RFC 7591
2. **OAuth Authorization** - User authorizes in browser
3. **Token Issuance** - Long-lived tokens for MCP access
4. **MCP Communication** - Bearer tokens for satellite access

## Implementation Status

### Completed Features

* RFC 6749 OAuth2 Authorization Server
* RFC 7591 Dynamic Client Registration
* PKCE support for public clients
* Database-backed client and token storage
* Team-scoped authorization
* MCP client support (VS Code, Cursor, Claude.ai)
* Dual authentication (cookies + Bearer tokens)
* Scope-based access control
* Token introspection endpoint
* State parameter URL encoding fix

### TODO Items

* **OAuthCleanupService Implementation** - Automated cleanup of expired tokens and clients
* **Comprehensive Logging** - Enhanced logging for monitoring and debugging
* **Metrics Collection** - Performance and usage metrics
* **Rate Limiting** - Protection against abuse
* **Client Management UI** - Admin interface for client management

## Related Documentation

* [Backend Authentication System](/development/backend/auth) - Core authentication
* [Satellite OAuth Authentication](/development/satellite/oauth-authentication) - MCP client authentication
* [Security Policy](/development/backend/security) - Security details
* [API Documentation](/development/backend/api/) - API reference
* [OAuth Provider Implementation](/development/backend/oauth-providers) - Third-party OAuth login setup
