llms.py
Deployment

GitHub OAuth Setup

Secure your llms.py deployment with GitHub OAuth authentication

Overview

The github_auth built-in extension enables OAuth 2.0 authentication via GitHub for your llms application. When enabled, users must sign in with their GitHub account before accessing the application.

Key Features

  • ✅ GitHub OAuth 2.0 integration
  • ✅ Secure session management
  • ✅ CSRF protection with state tokens
  • ✅ User profile display with avatar
  • ✅ Logout functionality
  • ✅ Optional user access restrictions
  • ✅ Environment variable support

Configuration

Create a config file at ~/.llms/users/default/github_auth/config.json:

{
  "enabled": true,
  "client_id": "GITHUB_CLIENT_ID",
  "client_secret": "GITHUB_CLIENT_SECRET",
  "redirect_uri": "http://localhost:8000/auth/github/callback",
  "restrict_to": "GITHUB_USERS"
}
PropertyDescription
client_idGitHub OAuth App client ID
client_secretGitHub OAuth App client secret
redirect_uriCallback URL registered with GitHub
restrict_toOptional comma/space-delimited list of allowed GitHub usernames
enabledSet to false to disable the extension

Values prefixed with $ are resolved from environment variables.

Creating a GitHub OAuth App

  1. Go to GitHub Developer Settings
  2. Click New OAuth App
  3. Fill in the application details:
    • Application name: Your app name
    • Homepage URL: Your app's homepage (e.g., http://localhost:8000)
    • Authorization callback URL: Must match your redirect_uri (e.g., http://localhost:8000/auth/github/callback)
  4. Click Register application
  5. Copy the Client ID and generate a Client Secret

For production deployments, use your actual domain instead of localhost.

2. Configure Environment Variables

Set the following environment variables:

export GITHUB_CLIENT_ID="your_github_client_id_here"
export GITHUB_CLIENT_SECRET="your_github_client_secret_here"

# Optional - Comma or space separated list of allowed users
export GITHUB_USERS="octocat mythz"

For permanent configuration, add these to your shell profile (~/.bashrc, ~/.zshrc, etc.).

3. Start the Server

llms --serve 8000

Or with Docker:

docker run -p 8000:8000 \
  -e GITHUB_CLIENT_ID="$GITHUB_CLIENT_ID" \
  -e GITHUB_CLIENT_SECRET="$GITHUB_CLIENT_SECRET" \
  -e GITHUB_USERS="$GITHUB_USERS" \
  -e GROQ_API_KEY="$GROQ_API_KEY" \
  ghcr.io/servicestack/llms:latest

Usage

Signing In

  1. Navigate to http://localhost:8000
  2. Click "Sign in with GitHub"
  3. Authorize the application on GitHub
  4. You'll be redirected back to the application, now authenticated

Signing Out

  1. Click on your avatar in the top-right corner
  2. A dropdown menu will appear showing your profile info
  3. Click "Sign Out"

Restricted Access

If restrict_to is configured, only specified GitHub users can access the application:

{
  "restrict_to": "octocat mythz demisbellot"
}

Users not in this list receive a 403 Forbidden response.

Disable Authentication

You can disable the GitHub OAuth extension by setting enabled to false:

{
  "enabled": true,
  ...
}

Or remove the entire ~/.llms/users/default/github_auth/config.json file.

Production Configuration

For production, update the redirect_uri:

{
  "client_id": "GITHUB_CLIENT_ID",
  "client_secret": "GITHUB_CLIENT_SECRET",
  "redirect_uri": "https://yourdomain.com/auth/github/callback",
  "restrict_to": "GITHUB_USERS"
}

Also update the callback URL in your GitHub OAuth App settings.

Architecture

API Endpoints

The extension registers these routes:

MethodEndpointDescription
GET/authCheck authentication status
GET/auth/githubInitiate GitHub OAuth flow
GET/auth/github/callbackOAuth callback handler
GET/auth/sessionGet current session info
POST/auth/logoutEnd the current session

Session Management

  • Sessions stored in-memory (g_sessions dictionary)
  • Session tokens are 32-byte URL-safe random strings
  • Sessions expire after 24 hours
  • CSRF protection using state tokens (expire after 10 minutes)

OAuth Flow

┌─────────┐          ┌─────────┐          ┌────────┐
│ Browser │          │  llms   │          │ GitHub │
└────┬────┘          └────┬────┘          └───┬────┘
     │                    │                   │
     │ GET /auth/github   │                   │
     ├───────────────────►│                   │
     │                    │                   │
     │   302 Redirect     │                   │
     │◄───────────────────┤                   │
     │                    │                   │
     │  /login/oauth/authorize?...            │
     ├────────────────────────────────────────►
     │                    │                   │
     │         User grants access             │
     │◄────────────────────────────────────────
     │                    │                   │
     │ GET /auth/github/callback?code=...     │
     ├───────────────────►│                   │
     │                    │                   │
     │                    │ POST /access_token │
     │                    ├──────────────────►│
     │                    │                   │
     │                    │   access_token    │
     │                    │◄──────────────────┤
     │                    │                   │
     │                    │ GET /user         │
     │                    ├──────────────────►│
     │                    │                   │
     │                    │   user info       │
     │                    │◄──────────────────┤
     │                    │                   │
     │  302 /?session=... │                   │
     │  Set-Cookie: token │                   │
     │◄───────────────────┤                   │
     │                    │                   │
  1. User clicks "Sign in with GitHub" → redirects to /auth/github
  2. Server generates CSRF state token and redirects to GitHub
  3. User authorizes the app on GitHub
  4. GitHub redirects back with authorization code
  5. Server exchanges code for access token
  6. Server fetches user info from GitHub API
  7. Server creates session and sets cookie

Session Data Structure

{
  "userId": "12345678",
  "userName": "octocat",
  "displayName": "The Octocat",
  "profileUrl": "https://avatars.githubusercontent.com/u/583231",
  "email": "[email protected]",
  "sessionToken": "abc123...",
  "created": 1234567890.123
}

UI Component

The github_auth extension provides a custom SignIn component that displays a "Sign in with GitHub" button. This component automatically overrides the default sign-in UI when the extension is loaded.

export default {
    install(ctx) {
        // Override SignIn component
        ctx.components({
            SignIn,
        })
    }
}

Security

CSRF Protection

  • State tokens are generated for each OAuth flow
  • State tokens are validated on callback
  • Expired state tokens (>10 minutes) are automatically cleaned up

Session Security

  • Session tokens are cryptographically random (32 bytes)
  • Sessions expire after 24 hours
  • Expired sessions are automatically cleaned up
  • Session tokens transmitted via URL parameter (initial) and HTTP header (subsequent)

Best Practices

  1. Use HTTPS in Production: Always use TLS for production deployments
  2. Rotate Secrets: Regularly rotate GitHub OAuth client secrets
  3. Environment Variables: Never commit credentials to version control
  4. Minimal Scope: OAuth app only requests minimal required scopes
  5. Session Expiry: 24-hour expiry balances security and convenience

Troubleshooting

"GitHub OAuth not configured" error

  • Ensure GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET are set
  • Restart the server after setting environment variables
  • Verify environment variables are expanded in config

"Invalid state parameter" error

  • OAuth flow took longer than 10 minutes
  • Try the sign-in process again

"Invalid or expired session" error

  • Session expired (24-hour limit)
  • Sign in again to create a new session

"Access Denied" error

  • Your GitHub username is not in the restrict_to list
  • Contact the administrator to be added
  • Or remove restrict_to to allow all users

Callback URL mismatch

  • Ensure redirect_uri in llms.json matches GitHub OAuth App settings exactly
  • For localhost: http://localhost:8000/auth/github/callback
  • For production: https://yourdomain.com/auth/github/callback

Production Considerations

Persistent Sessions

For production with multiple instances, consider:

  1. Redis: Store sessions in Redis for sharing across instances
  2. Database: Use PostgreSQL or similar for session storage
  3. Sticky Sessions: Configure load balancer for sticky sessions

HTTPS/TLS

Always use HTTPS in production:

  1. Certificate: Obtain SSL/TLS certificate (Let's Encrypt)
  2. Reverse Proxy: Use nginx or Traefik with TLS termination
  3. HSTS: Enable HTTP Strict Transport Security
  4. Secure Cookies: Use secure flag for session cookies

Monitoring

Monitor authentication:

  1. Failed Attempts: Track failed login attempts
  2. Active Sessions: Monitor active session count
  3. Session Duration: Track how long users stay authenticated
  4. Access Logs: Log authentication events

Docker Deployment

With docker compose:

version: '3.8'

services:
  llms:
    image: ghcr.io/servicestack/llms:latest
    ports:
      - "8000:8000"
    environment:
      - GITHUB_CLIENT_ID=${GITHUB_CLIENT_ID}
      - GITHUB_CLIENT_SECRET=${GITHUB_CLIENT_SECRET}
      - GITHUB_USERS=${GITHUB_USERS}
      - OPENROUTER_API_KEY=${OPENROUTER_API_KEY}
      - GROQ_API_KEY=${GROQ_API_KEY}
    volumes:
      - llms-data:/home/llms/.llms
    restart: unless-stopped

volumes:
  llms-data:

Create .env file:

GITHUB_CLIENT_ID=your_client_id
GITHUB_CLIENT_SECRET=your_client_secret
GITHUB_USERS=octocat mythz
OPENROUTER_API_KEY=sk-or-...
GROQ_API_KEY=gsk_...

Start:

docker compose up -d

Next Steps