OAuth Security Best Practices
This guide covers security best practices for implementing OAuth authentication in your UIGen application.
State Parameter (CSRF Protection)
What UIGen Does Automatically
UIGen automatically implements CSRF protection using the OAuth state parameter:
- Generation: Creates a cryptographically secure random state (128-bit entropy)
- Storage: Stores state in sessionStorage (browser-side, single-use)
- Validation: Validates state on callback before exchanging code for token
- Cleanup: Removes state after successful validation
Why This Matters
The state parameter prevents Cross-Site Request Forgery (CSRF) attacks where an attacker tricks a user into authorizing their malicious application.
Without state validation:
Attacker → Victim clicks malicious link → Victim authorizes attacker's app → Attacker gains access
With state validation:
Attacker → Victim clicks malicious link → State mismatch → Authorization rejected ✓
Token Storage
Where Tokens Are Stored
UIGen stores OAuth tokens in browser localStorage:
| Token Type | Storage Location | Purpose |
|---|---|---|
| Access Token | localStorage | API authentication |
| Refresh Token | localStorage | Token renewal |
| State Parameter | sessionStorage | CSRF protection (temporary) |
| User Profile | localStorage | User information |
Security Considerations
localStorage Security:
- ✅ Persists across browser sessions
- ✅ Isolated per origin (domain)
- ⚠️ Accessible to JavaScript (XSS risk)
- ⚠️ Not sent automatically with requests
Mitigation Strategies:
- Content Security Policy (CSP): Prevent XSS attacks
- HTTPS Only: Protect tokens in transit
- Token Expiration: Use short-lived access tokens
- Refresh Tokens: Rotate tokens regularly
Example CSP Header
Content-Security-Policy:
default-src 'self';
script-src 'self' 'unsafe-inline' 'unsafe-eval';
connect-src 'self' https://api.yourdomain.com;
HTTPS Requirements
Development vs Production
Development (localhost):
- HTTP is acceptable:
http://localhost:3000/auth/callback - OAuth providers allow HTTP for localhost
Production:
- HTTPS is required:
https://yourdomain.com/auth/callback - Most providers reject HTTP redirect URIs in production
- Protects tokens from man-in-the-middle attacks
Why HTTPS Matters
Without HTTPS:
- Tokens can be intercepted in transit
- Authorization codes can be stolen
- User credentials can be compromised
Redirect URI Validation
Best Practices
- Exact Match: Redirect URI must match exactly (including trailing slashes)
- Whitelist Approach: Register only necessary redirect URIs
- No Wildcards: Avoid wildcard redirect URIs (most providers don't support them)
- Separate Environments: Use different redirect URIs for dev/staging/production
Common Mistakes
❌ Bad:
redirectUri: http://example.com/auth/callback/ # Trailing slash
✅ Good:
redirectUri: http://example.com/auth/callback # No trailing slash
❌ Bad:
redirectUri: http://*.example.com/auth/callback # Wildcard
✅ Good:
# Register each subdomain separately
redirectUri: https://app.example.com/auth/callback
Scope Minimization
Principle of Least Privilege
Only request the OAuth scopes your application actually needs.
❌ Bad (requesting unnecessary scopes):
scopes:
- openid
- email
- profile
- read:user
- repo # Not needed
- admin:org # Not needed
- delete:repo # Dangerous!
✅ Good (minimal scopes):
scopes:
- openid
- email
- profile
Why This Matters
- User Trust: Users are more likely to authorize apps requesting fewer permissions
- Security: Limits damage if tokens are compromised
- Compliance: Reduces data privacy concerns
Token Lifecycle Management
Access Token Expiration
Most OAuth providers issue short-lived access tokens (1-2 hours).
UIGen Behavior:
- Detects 401 Unauthorized responses
- Automatically attempts token refresh
- Retries original request with new token
- Redirects to login if refresh fails
Refresh Token Rotation
Some providers rotate refresh tokens on each use:
Old Refresh Token → Token Refresh Request → New Access Token + New Refresh Token
UIGen automatically handles refresh token rotation.
Token Revocation
Users can revoke access at any time through provider settings:
- Google: Google Account Permissions
- GitHub: Authorized OAuth Apps
- Microsoft: Account Privacy
Your Application Should:
- Handle 401 errors gracefully
- Redirect to login when tokens are invalid
- Clear stored tokens on logout
Client Secret Management
Public vs Confidential Clients
Public Clients (UIGen default):
- Client-side applications (browsers, mobile apps)
- Cannot securely store client secrets
- Use PKCE (Proof Key for Code Exchange) when available
Confidential Clients:
- Server-side applications
- Can securely store client secrets
- Use client secret for token exchange
Never Expose Client Secrets
❌ Never do this:
# DON'T: Hardcode secrets in OpenAPI spec
x-uigen-auth:
providers:
- provider: google
clientId: "123456.apps.googleusercontent.com"
clientSecret: "GOCSPX-abc123" # NEVER DO THIS!
✅ Do this instead:
# Use environment variables
x-uigen-auth:
providers:
- provider: google
clientId: ${GOOGLE_CLIENT_ID}
# No client secret needed for public OAuth flows
XSS (Cross-Site Scripting) Prevention
Content Security Policy
Implement a strict CSP to prevent XSS attacks:
<meta http-equiv="Content-Security-Policy"
content="default-src 'self';
script-src 'self';
style-src 'self' 'unsafe-inline';">
Input Sanitization
UIGen automatically sanitizes user inputs, but you should also:
- Validate API responses: Don't trust data from OAuth providers
- Escape user-generated content: Sanitize before displaying
- Use framework protections: React automatically escapes JSX content
Session Management
Logout Best Practices
When users log out:
- ✅ Clear access token from localStorage
- ✅ Clear refresh token from localStorage
- ✅ Clear user profile from localStorage
- ✅ Clear auth method from localStorage
- ✅ Redirect to login page
- ⚠️ Consider revoking tokens with provider (optional)
UIGen handles steps 1-5 automatically.
Session Timeout
Consider implementing session timeout for sensitive applications:
// Example: 30-minute session timeout
const SESSION_TIMEOUT = 30 * 60 * 1000; // 30 minutes
let lastActivity = Date.now();
// Update on user activity
document.addEventListener('click', () => {
lastActivity = Date.now();
});
// Check timeout periodically
setInterval(() => {
if (Date.now() - lastActivity > SESSION_TIMEOUT) {
// Log user out
clearAuthCredentials();
window.location.href = '/login';
}
}, 60000); // Check every minute
Rate Limiting
Provider Rate Limits
OAuth providers enforce rate limits:
| Provider | Rate Limit | Scope |
|---|---|---|
| 10,000 requests/day | Per project | |
| GitHub | 5,000 requests/hour | Per user |
| Microsoft | Varies by endpoint | Per app |
Best Practices
- Cache user profiles: Don't fetch on every request
- Implement exponential backoff: Retry with increasing delays
- Monitor usage: Track API calls to avoid limits
- Handle 429 responses: Respect rate limit headers
Monitoring and Logging
What to Log
✅ Do log:
- Authentication attempts (success/failure)
- Token refresh attempts
- OAuth errors (with error codes)
- Unusual activity patterns
❌ Never log:
- Access tokens
- Refresh tokens
- Client secrets
- Authorization codes
Example Logging
// Good logging
console.log('[OAuth] Authentication successful', {
provider: 'google',
userId: 'user123',
timestamp: new Date().toISOString()
});
// Bad logging - NEVER DO THIS
console.log('[OAuth] Token:', accessToken); // ❌ NEVER LOG TOKENS
Compliance Considerations
GDPR (EU)
If serving EU users:
- Consent: Obtain explicit consent before OAuth
- Data Minimization: Request minimal scopes
- Right to Deletion: Implement account deletion
- Data Portability: Allow users to export their data
CCPA (California)
If serving California users:
- Privacy Policy: Disclose data collection practices
- Opt-Out: Provide opt-out mechanisms
- Data Access: Allow users to access their data
Security Checklist
Before deploying to production:
- HTTPS enabled for all OAuth redirect URIs
- State parameter validation implemented (automatic in UIGen)
- Minimal OAuth scopes requested
- Client secrets not exposed in client-side code
- Content Security Policy configured
- Token storage secured (localStorage with CSP)
- Session timeout implemented (if needed)
- Logout clears all tokens and user data
- Rate limiting handled gracefully
- Error logging implemented (without logging tokens)
- Privacy policy updated with OAuth data collection
- Terms of service updated
- OAuth app verified with providers (if required)
Incident Response
If Tokens Are Compromised
-
Immediate Actions:
- Revoke compromised tokens with OAuth provider
- Force logout all users
- Rotate client secrets (if applicable)
- Investigate breach source
-
Communication:
- Notify affected users
- Document incident
- Report to authorities if required (GDPR, etc.)
-
Prevention:
- Review security measures
- Implement additional monitoring
- Update security policies
Next Steps
- OAuth Troubleshooting - Common issues and solutions
- Google OAuth Setup - Provider-specific setup
- GitHub OAuth Setup - Provider-specific setup