DeployStack Docs

Gateway OAuth Implementation

The DeployStack Gateway implements an OAuth2 client for secure CLI authentication with the DeployStack backend. This enables users to authenticate via their browser and use the CLI with proper access tokens.

Architecture Overview

The gateway acts as an OAuth2 client implementing the Authorization Code flow with PKCE (Proof Key for Code Exchange) for enhanced security. The implementation consists of:

  • OAuth2 Client - Handles the complete authorization flow
  • Callback Server - Temporary HTTP server for receiving authorization codes
  • API Client - Makes authenticated requests to backend APIs
  • Credential Storage - Secure token storage and retrieval

OAuth2 Flow Process

1. Authorization Request

When a user runs the login command, the CLI:

  • Generates a cryptographically secure PKCE code verifier (128 random bytes)
  • Creates a SHA256 code challenge from the verifier
  • Generates a random state parameter for CSRF protection
  • Builds the authorization URL with all required OAuth2 parameters
  • Opens the user's default browser to the authorization endpoint
  • Starts a temporary callback server on localhost port 8976

The authorization URL includes:

  • response_type=code for authorization code flow
  • client_id=deploystack-gateway-cli for client identification
  • redirect_uri=http://localhost:8976/oauth/callback for callback handling
  • Requested scopes (see OAuth Scope Management below)
  • PKCE parameters: code_challenge and code_challenge_method=S256
  • Random state parameter for security

2. User Authorization

The browser opens to the backend's consent page where the user:

  • Reviews the requested permissions and scopes
  • Sees security warnings about CLI access
  • Can approve or deny the authorization request
  • Is redirected back to the CLI's callback server upon decision

3. Callback Handling

The temporary callback server:

  • Listens only on localhost for security
  • Validates the callback path (/oauth/callback)
  • Extracts the authorization code and state parameters
  • Validates the state parameter matches the original request
  • Displays a success or error page to the user
  • Automatically shuts down after receiving the callback

4. Token Exchange with Device Registration

After receiving the authorization code, the CLI:

  • Detects device information (hostname, OS, hardware fingerprint)
  • Exchanges the code for access and refresh tokens
  • Includes the PKCE code verifier for verification
  • Automatically registers the device during token exchange
  • Validates the token response from the backend
  • Fetches user information using the new access token
  • Stores credentials securely for future use

Automatic Device Registration

During the token exchange process, the gateway automatically registers the current device with the backend for security and management purposes:

Device Information Collected:

  • device_name: User-friendly name (defaults to hostname)
  • hostname: System hostname
  • hardware_id: Unique hardware fingerprint based on MAC addresses and system info
  • os_type: Operating system (macOS, Windows, Linux)
  • os_version: OS version string
  • arch: System architecture (x64, arm64, etc.)
  • node_version: Node.js version for compatibility tracking
  • user_agent: CLI version and platform information

Security Benefits:

  • Device registration happens only during authenticated login sessions
  • No separate device registration endpoints exist - this prevents unauthorized device registration and enhances security
  • Hardware fingerprinting provides unique device identification
  • Enables device management and access control in the backend
  • Eliminates the need for manual device registration API calls

Process Flow:

  1. Gateway detects current device information using system APIs
  2. Device info is included in the OAuth2 token request
  3. Backend validates the token request and registers the device
  4. Device information is returned in the token response
  5. Gateway logs successful device registration to the user (e.g., "📱 Device registered: MacBook-Pro.local")

Error Handling: If device registration fails during token exchange:

  • The OAuth2 login process continues successfully
  • User authentication is not affected
  • Device context may be limited for some features
  • Error is logged but doesn't break the login flow

PKCE Security Implementation

The gateway implements PKCE (Proof Key for Code Exchange) following RFC 7636:

  • Code Verifier: 128 random bytes encoded as base64url
  • Code Challenge: SHA256 hash of the verifier, base64url encoded
  • Challenge Method: Always uses S256 (SHA256)
  • State Validation: Cryptographically secure random state parameter

PKCE provides security benefits:

  • Prevents authorization code interception attacks
  • No client secret required (suitable for public clients)
  • Protects against malicious applications

Client Configuration

The gateway is pre-registered with the backend as:

  • Client ID: deploystack-gateway-cli
  • Client Type: Public client (no secret required)
  • Redirect URIs: http://localhost:8976/oauth/callback, http://127.0.0.1:8976/oauth/callback
  • Allowed Scopes: See source code at services/gateway/src/utils/auth-config.ts
  • PKCE: Required with SHA256 method
  • Token Lifetime: 1 week access tokens, 30 day refresh tokens

Command Integration

Login Command

The login command orchestrates the complete OAuth2 flow:

  • Checks if the user is already authenticated
  • Displays "already logged in" message if credentials are valid
  • Initiates the OAuth2 flow if authentication is needed
  • Handles browser opening and callback server management
  • Stores credentials securely upon successful authentication
  • Provides clear success confirmation with user email

Authenticated Commands

Commands like whoami, teams, and start use stored credentials:

  • Check authentication status before proceeding
  • Display helpful error messages if not authenticated
  • Use Bearer token authentication for API requests
  • Automatically refresh expired tokens when possible
  • Handle token expiration gracefully

Error Handling

The OAuth implementation includes comprehensive error handling:

Error Types

  • TIMEOUT: OAuth callback not received within time limit
  • ACCESS_DENIED: User denied the authorization request
  • BROWSER_ERROR: Failed to open browser automatically
  • NETWORK_ERROR: Network connectivity issues
  • STORAGE_ERROR: Failed to store credentials securely
  • TOKEN_EXPIRED: Access token has expired
  • INVALID_TOKEN: Token format or signature invalid
  • INVALID_GRANT: Authorization code or refresh token invalid

User Guidance

Each error type provides specific user guidance:

  • Timeout errors suggest retrying the command
  • Access denied errors explain the approval requirement
  • Browser errors offer manual URL opening
  • Network errors suggest connectivity checks
  • Storage errors indicate keychain permission issues

Browser Integration

The CLI provides seamless browser integration:

  • Automatic Opening: Uses the system's default browser
  • Cross-Platform: Works on Windows, macOS, and Linux
  • Fallback Handling: Displays manual URL if auto-open fails
  • User Feedback: Clear messages about browser actions
  • Security Warnings: Alerts for development server usage

Token Management

Token Refresh

The gateway automatically handles token refresh:

  • Monitors token expiration with 5-minute buffer
  • Attempts refresh before tokens expire
  • Uses refresh tokens for seamless re-authentication
  • Falls back to full re-authentication if refresh fails
  • Updates stored credentials with new tokens

Token Validation

Before each API request, the gateway:

  • Checks token expiration locally
  • Validates token format and structure
  • Handles 401 responses with automatic refresh
  • Provides clear error messages for invalid tokens

Development vs Production

The OAuth client adapts to different environments:

Development Mode

  • Uses HTTP for localhost callback server
  • Accepts self-signed certificates for development
  • Displays security warnings for non-production servers
  • Provides detailed error information for debugging

Production Mode

  • Enforces HTTPS for all communications
  • Validates SSL certificates strictly
  • Uses secure callback URLs
  • Limits error information exposure

Integration with Backend

The gateway OAuth client integrates with the backend OAuth2 server:

  • Client Registration: Pre-registered with known client ID
  • PKCE Support: Uses SHA256 method as required by backend
  • Scope Validation: Requests only backend-supported scopes
  • Token Format: Handles backend's custom JWT-like token format
  • Error Responses: Processes standard OAuth2 error responses
  • Endpoint Discovery: Uses standard OAuth2 endpoint paths
  • Device Registration: Automatic device registration during token exchange

Device Management Integration

The gateway's device registration integrates seamlessly with the backend's device management system:

Backend Integration Points:

  • OAuth2 Token Endpoint: Extended to accept optional device_info in token requests
  • Device Service: Uses existing DeviceService.registerOrUpdateDevice() method
  • Database Storage: Device information stored in the devices table
  • User Association: Devices automatically linked to the authenticated user

Token Request Enhancement: The gateway includes device information in the OAuth2 token request:

{
  "grant_type": "authorization_code",
  "code": "authorization_code_here",
  "redirect_uri": "http://localhost:8976/oauth/callback",
  "client_id": "deploystack-gateway-cli",
  "code_verifier": "pkce_verifier_here",
  "device_info": {
    "device_name": "MacBook-Pro.local",
    "hostname": "MacBook-Pro.local",
    "hardware_id": "a1b2c3d4e5f6789012345678901234ab",
    "os_type": "macOS",
    "os_version": "14.2.1",
    "arch": "arm64",
    "node_version": "v20.10.0",
    "user_agent": "DeployStack-CLI/1.0.0 (darwin; arm64)"
  }
}

Token Response Enhancement: When device registration succeeds, the backend includes device information in the token response:

{
  "access_token": "...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "...",
  "scope": "mcp:read account:read...",
  "device": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "device_name": "MacBook-Pro.local",
    "is_active": true,
    "is_trusted": true,
    "created_at": "2025-08-23T10:20:30Z"
  }
}

Security Design:

  • Device registration only occurs during authenticated OAuth2 flows
  • No separate device creation endpoints exist - this architectural decision prevents unauthorized device registration and eliminates potential security vulnerabilities
  • Hardware fingerprinting ensures unique device identification across multiple login sessions
  • Device information is validated using JSON schema before processing
  • Gateway automatically handles device lookup using hardware fingerprints without requiring manual registration

For comprehensive information about device management and hardware fingerprinting, see the Device Management Documentation.

Security Considerations

The OAuth implementation follows security best practices:

  • PKCE Required: All authorization requests use PKCE
  • State Validation: Prevents CSRF attacks
  • Localhost Binding: Callback server only accepts local connections
  • Timeout Protection: All operations have reasonable timeouts
  • Secure Storage: Credentials stored using OS keychain
  • No Secrets: Public client design eliminates secret management

For detailed security implementation including credential storage, token expiration, and local file security, see the Gateway Security Guide.

OAuth Scope Management

The gateway requests specific OAuth scopes during authentication to access backend APIs. Scope configuration must stay synchronized between the gateway and backend.

Current Scopes

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

  • Gateway scopes: services/gateway/src/utils/auth-config.ts in the scopes array
  • Backend validation: services/backend/src/services/oauth/authorizationService.ts in the validateScope() method

Adding New Scopes

When the backend adds support for a new OAuth scope, you must update the gateway configuration:

  1. Add the scope to the scopes array in services/gateway/src/utils/auth-config.ts
  2. Add a description to the SCOPE_DESCRIPTIONS object in the same file
  3. Test the login flow to ensure the new scope is requested and granted

Example:

// In services/gateway/src/utils/auth-config.ts
scopes: [
  'mcp:read',
  'mcp:categories:read',
  'your-new-scope',  // Add new scope here
  // ... other scopes
],

// And add description
export const SCOPE_DESCRIPTIONS: Record<string, string> = {
  'mcp:read': 'Access your MCP server installations and configurations',
  'your-new-scope': 'Description of what this scope allows',  // Add description
  // ... other descriptions
};

Scope Synchronization

Critical: The gateway and backend must have matching scope configurations:

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

Always coordinate scope changes between both services.

Testing OAuth Flow

During development, the OAuth flow can be tested:

  1. Start the backend in development mode
  2. Build the gateway CLI
  3. Run the login command with development URL
  4. Complete the browser authorization flow
  5. Verify authentication with the whoami command

The OAuth implementation provides a secure, user-friendly authentication experience that follows industry standards while integrating seamlessly with the DeployStack backend.