OAuth 2.0 GitHub Integration
Overview
This document describes the implementation of OAuth 2.0 GitHub integration for Anchorpipe, allowing users to authenticate using their GitHub credentials instead of creating and managing a separate password.
Story: ST-207
Status: Implemented
Priority: P0
Features
- OAuth 2.0 Authorization Code Flow with PKCE: Secure authentication flow using Proof Key for Code Exchange
- Account Linking: Automatically links GitHub accounts to existing users by email
- Token Encryption: OAuth tokens are encrypted at rest using AES-256-GCM
- Session Management: Creates secure JWT sessions after successful authentication
- Audit Logging: All OAuth authentication events are logged for security monitoring
Architecture
Flow Diagram
User → Login Page → GitHub OAuth → GitHub Authorization → Callback → Token Exchange → User Profile → Account Linking → Session Creation → Dashboard
Components
-
OAuth Initiation (
/api/auth/oauth/github)- Generates PKCE code verifier and state
- Stores values in secure HTTP-only cookies
- Redirects to GitHub authorization page
-
OAuth Callback (
/api/auth/callback/github)- Validates state (CSRF protection)
- Exchanges authorization code for access token
- Fetches user profile from GitHub
- Links or creates user account
- Creates session and redirects to dashboard
-
Account Linking Service (
oauth-service.ts)- Handles three scenarios:
- Existing OAuth account: Updates tokens and user info
- Existing user by email: Links GitHub account
- New user: Creates user and OAuth account
- Handles three scenarios:
Setup
1. Create GitHub OAuth App
- Go to GitHub Settings → Developer settings → OAuth Apps
- Click "New OAuth App"
- Fill in:
- Application name: Anchorpipe (or your app name)
- Homepage URL:
https://your-domain.com - Authorization callback URL:
https://your-domain.com/api/auth/callback/github
- Click "Register application"
- Copy the Client ID and generate a Client Secret
2. Environment Variables
Add the following environment variables to your .env file:
# GitHub OAuth Configuration
GITHUB_CLIENT_ID=your_github_client_id
GITHUB_CLIENT_SECRET=your_github_client_secret
# Required for token encryption (from ST-202)
ENCRYPTION_KEY_BASE64=your_base64_encoded_32_byte_key
# Required for session management
AUTH_SECRET=your_auth_secret_at_least_16_chars
3. Generate Encryption Key
If you haven't already set up encryption (from ST-202), generate a 32-byte key:
# Generate a random 32-byte key and encode to base64
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
Copy the output to ENCRYPTION_KEY_BASE64.
API Endpoints
GET /api/auth/oauth/github
Initiates the OAuth flow by redirecting to GitHub.
Query Parameters:
return_to(optional): URL to redirect to after successful login (default:/dashboard)
Response:
- Redirects to GitHub authorization page
Example:
GET /api/auth/oauth/github?return_to=/dashboard
GET /api/auth/callback/github
Handles the OAuth callback from GitHub.
Query Parameters:
code: Authorization code from GitHubstate: State token for CSRF protectionerror(optional): Error code from GitHuberror_description(optional): Error description from GitHub
Response:
- Redirects to dashboard on success
- Redirects to login page with error on failure
Security Features
PKCE (Proof Key for Code Exchange)
- Code Verifier: Random 32-byte value, base64url-encoded
- Code Challenge: SHA256 hash of verifier, base64url-encoded
- Method: S256 (SHA256)
- Prevents authorization code interception attacks
CSRF Protection
- State Token: Random 32-byte value stored in HTTP-only cookie
- Validation: State from callback must match stored value
- Prevents cross-site request forgery attacks
Token Security
- Encryption: OAuth tokens encrypted at rest using AES-256-GCM
- Storage: Tokens stored in
accountstable with encrypted fields - Transmission: Tokens transmitted over HTTPS only
Session Security
- JWT Tokens: Signed with
AUTH_SECRET - HTTP-Only Cookies: Prevents XSS attacks
- Secure Flag: Enabled in production
- SameSite: Lax (prevents CSRF)
User Experience
Login Flow
- User clicks "Sign in with GitHub" on login page
- Redirected to GitHub authorization page
- User authorizes the application
- Redirected back to Anchorpipe
- Automatically logged in and redirected to dashboard
Account Linking
- Existing OAuth Account: User is logged in, tokens updated
- Existing Email: GitHub account is linked to existing user account
- New User: New user account is created with GitHub profile
Error Handling
Common Errors
-
Invalid State: State mismatch (possible CSRF attack)
- Redirects to login with error message
- Logged as security event
-
Token Exchange Failure: Invalid or expired authorization code
- Redirects to login with error message
- Logged as authentication failure
-
GitHub API Error: Failed to fetch user profile
- Redirects to login with error message
- Logged as authentication failure
Error Messages
Errors are displayed to users via URL query parameters:
error=oauth_error&message=...error=invalid_state&message=...error=oauth_failed&message=...
Audit Logging
All OAuth events are logged to the audit log:
- login_success: Successful OAuth login
- login_failure: Failed OAuth authentication
- user_created: New user created via OAuth
Log entries include:
- User ID (if available)
- GitHub ID and login
- IP address and user agent
- Error details (for failures)
Testing
Unit Tests
Run unit tests for OAuth utilities:
npm test -- oauth.test.ts
npm test -- base64.test.ts
Manual Testing
-
First-time Login:
- Click "Sign in with GitHub"
- Authorize on GitHub
- Verify new user account created
- Verify session created
-
Returning User:
- Click "Sign in with GitHub"
- Authorize on GitHub
- Verify existing account used
- Verify tokens updated
-
Account Linking:
- Create account with email/password
- Log in with GitHub using same email
- Verify accounts linked
-
Error Cases:
- Cancel GitHub authorization
- Test with invalid state
- Test with expired code
Troubleshooting
"GITHUB_CLIENT_ID must be set"
- Ensure
GITHUB_CLIENT_IDis set in environment variables - Restart the application after setting environment variables
"GITHUB_CLIENT_SECRET must be set"
- Ensure
GITHUB_CLIENT_SECRETis set in environment variables - Verify the secret matches the GitHub OAuth app
"ENCRYPTION_KEY_BASE64 must be set"
- Ensure encryption key is configured (see ST-202 documentation)
- Key must be base64-encoded 32-byte value
"State mismatch" Error
- Usually indicates CSRF attack or expired OAuth flow
- Verify cookies are enabled in browser
- Check that OAuth flow completes within 10 minutes
Token Exchange Fails
- Verify callback URL matches GitHub OAuth app configuration
- Check that authorization code hasn't expired (codes expire quickly)
- Verify client ID and secret are correct
Future Enhancements
- Token Refresh: Implement refresh token rotation
- Multiple Providers: Support Google, GitLab, etc.
- Account Management: UI to link/unlink OAuth accounts
- Email Verification: Verify email when linking accounts
- Profile Sync: Periodic sync of GitHub profile data
Related Documentation
- Data Encryption - Token encryption
- Audit Logging - Authentication logging
- ST-104: Basic Authentication - Session management