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"
}| Property | Description |
|---|---|
client_id | GitHub OAuth App client ID |
client_secret | GitHub OAuth App client secret |
redirect_uri | Callback URL registered with GitHub |
restrict_to | Optional comma/space-delimited list of allowed GitHub usernames |
enabled | Set to false to disable the extension |
Values prefixed with $ are resolved from environment variables.
Creating a GitHub OAuth App
- Go to GitHub Developer Settings
- Click New OAuth App
- 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)
- Click Register application
- 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 8000Or 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:latestUsage
Signing In
- Navigate to
http://localhost:8000 - Click "Sign in with GitHub"
- Authorize the application on GitHub
- You'll be redirected back to the application, now authenticated
Signing Out
- Click on your avatar in the top-right corner
- A dropdown menu will appear showing your profile info
- 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:
| Method | Endpoint | Description |
|---|---|---|
| GET | /auth | Check authentication status |
| GET | /auth/github | Initiate GitHub OAuth flow |
| GET | /auth/github/callback | OAuth callback handler |
| GET | /auth/session | Get current session info |
| POST | /auth/logout | End the current session |
Session Management
- Sessions stored in-memory (
g_sessionsdictionary) - 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 │ │
│◄───────────────────┤ │
│ │ │- User clicks "Sign in with GitHub" → redirects to
/auth/github - Server generates CSRF state token and redirects to GitHub
- User authorizes the app on GitHub
- GitHub redirects back with authorization code
- Server exchanges code for access token
- Server fetches user info from GitHub API
- 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
- Use HTTPS in Production: Always use TLS for production deployments
- Rotate Secrets: Regularly rotate GitHub OAuth client secrets
- Environment Variables: Never commit credentials to version control
- Minimal Scope: OAuth app only requests minimal required scopes
- Session Expiry: 24-hour expiry balances security and convenience
Troubleshooting
"GitHub OAuth not configured" error
- Ensure
GITHUB_CLIENT_IDandGITHUB_CLIENT_SECRETare 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_tolist - Contact the administrator to be added
- Or remove
restrict_toto allow all users
Callback URL mismatch
- Ensure
redirect_uriinllms.jsonmatches 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:
- Redis: Store sessions in Redis for sharing across instances
- Database: Use PostgreSQL or similar for session storage
- Sticky Sessions: Configure load balancer for sticky sessions
HTTPS/TLS
Always use HTTPS in production:
- Certificate: Obtain SSL/TLS certificate (Let's Encrypt)
- Reverse Proxy: Use nginx or Traefik with TLS termination
- HSTS: Enable HTTP Strict Transport Security
- Secure Cookies: Use secure flag for session cookies
Monitoring
Monitor authentication:
- Failed Attempts: Track failed login attempts
- Active Sessions: Monitor active session count
- Session Duration: Track how long users stay authenticated
- 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