Authentication API
PadawanForge uses a connected accounts OAuth2 authentication system with support for multiple providers and account linking.
Base Path
/api/auth/
OAuth Providers
Google OAuth
Initiate Google Authentication
GET/POST /api/auth/google
Response:
- Redirects to Google OAuth consent screen with OpenID Connect support
- Uses
access_type: 'offline'for refresh tokens - After consent, redirects to callback URL
Google OAuth Callback
GET /api/auth/callback/google
Query Parameters:
code- Authorization code from Googlestate- CSRF protection token
Response:
- Creates or updates player session
- Creates connected account record
- Redirects to appropriate page based on onboarding status
Discord OAuth
Initiate Discord Authentication
GET/POST /api/auth/discord
Response:
- Redirects to Discord OAuth consent screen
- Requests
identifyandemailscopes - After consent, redirects to callback URL
Discord OAuth Callback
GET /api/auth/callback/discord
Query Parameters:
code- Authorization code from Discordstate- CSRF protection token
Response:
- Creates or updates player session
- Creates connected account record
- Redirects to appropriate page based on onboarding status
Provider Information
Available Providers
GET /api/auth/available-providers
Response:
{
"success": true,
"providers": {
"google": {
"available": true,
"clientId": "configured",
"clientSecret": "configured"
},
"discord": {
"available": true,
"clientId": "configured",
"clientSecret": "configured"
},
"apple": {
"available": false,
"clientId": "missing",
"clientSecret": "missing"
},
"slack": {
"available": false,
"clientId": "missing",
"clientSecret": "missing"
}
},
"availableProviders": ["google", "discord"],
"totalProviders": 4,
"configuredProviders": 2
}
Registration Flow
Complete Registration
POST /api/auth/complete-registration
Authentication: Required
Request Body:
{
"username": "string",
"birthday": "YYYY-MM-DD" // optional
}
Response:
{
"success": true,
"message": "Registration completed successfully",
"player": {
"displayName": "string",
"birthday": "YYYY-MM-DD",
"registrationCompleted": true
}
}
Complete Tutorial
POST /api/auth/complete-tutorial
Authentication: Required
Response:
{
"success": true,
"message": "Tutorial completed successfully",
"tutorialCompleted": true,
"onboardingCompletedAt": "2024-01-15T10:30:00Z"
}
Logout
GET/POST /api/auth/logout
Response:
- Clears session from KV storage
- Clears session cookie
- Redirects to home page
Connected Accounts
List Connected Accounts
GET /api/auth/connected-accounts
Authentication: Required
Response:
{
"success": true,
"connectedAccounts": [
{
"id": 1,
"provider": "google",
"providerUserId": "123456789",
"providerEmail": "user@gmail.com",
"providerUsername": "User Name",
"providerAvatar": "https://...",
"isPrimary": true,
"connectedAt": "2024-01-15T10:30:00Z",
"lastUsed": "2024-01-16T14:20:00Z"
},
{
"id": 2,
"provider": "discord",
"providerUserId": "987654321",
"providerEmail": "user@discord.com",
"providerUsername": "DiscordUser#1234",
"providerAvatar": "https://...",
"isPrimary": false,
"connectedAt": "2024-01-16T14:20:00Z",
"lastUsed": "2024-01-16T14:20:00Z"
}
]
}
Set Primary Provider
POST /api/auth/connected-accounts/set-primary/[provider]
Authentication: Required
Parameters:
provider- Provider ID (google, discord only)
Response:
{
"success": true,
"message": "discord set as primary account"
}
Disconnect Account
DELETE /api/auth/connected-accounts/disconnect/[provider]
Authentication: Required
Parameters:
provider- Provider ID to disconnect
Response:
{
"success": true,
"message": "discord account disconnected successfully"
}
Error Cases:
- Cannot disconnect the only remaining account
- Cannot disconnect primary account without having another connected account
Session Information
Session data is automatically included in authenticated requests and contains:
{
"id": "session_uuid",
"playerId": "player_uuid",
"playerUuid": "public_uuid",
"defaultProvider": "google",
"currentProvider": "google",
"provider": "google",
"email": "user@example.com",
"username": "User Name",
"avatar": "https://...",
"level": 5,
"experience": 1250,
"birthday": "1990-01-01",
"location": "San Francisco, CA",
"gender": "Prefer not to say",
"registrationCompleted": true,
"tutorialCompleted": true,
"onboardingCompletedAt": "2024-01-15T10:30:00Z",
"createdAt": "2024-01-15T10:30:00Z",
"expiresAt": "2024-01-22T10:30:00Z"
}
OAuth Configuration
Google OAuth Setup
- Create project in Google Cloud Console
- Enable Google+ API
- Configure OAuth consent screen with OpenID Connect
- Create OAuth 2.0 credentials
- Set authorized redirect URIs:
https://yourdomain.com/api/auth/callback/google
- Configure environment variables:
OAUTH_GOOGLE_CLIENT_IDOAUTH_GOOGLE_CLIENT_SECRET
Discord OAuth Setup
- Create application in Discord Developer Portal
- Configure OAuth2 settings
- Set redirect URIs:
https://yourdomain.com/api/auth/callback/discord
- Request required scopes:
identify,email - Configure environment variables:
OAUTH_DISCORD_CLIENT_IDOAUTH_DISCORD_CLIENT_SECRET
Error Responses
Authentication endpoints return simple error responses:
{
"error": "Error description"
}
Common Error Types
Unauthorized Access
{
"error": "Unauthorized"
}
Invalid Provider
{
"error": "Invalid provider"
}
Registration/Validation Errors
{
"error": "Display name is required"
}
{
"error": "Invalid birthday format"
}
Database/System Errors
{
"error": "Database not available"
}
{
"error": "Failed to complete registration"
}
Account Management Errors
{
"error": "Failed to set primary account"
}
{
"error": "Cannot disconnect the last connected account"
}
Security Features
- CSRF Protection: State parameter validation for all OAuth flows
- Secure Sessions: Cloudflare KV-based session storage with automatic expiration
- Cookie Security: HttpOnly, Secure (production), SameSite=Lax
- Session Expiration: 7-day automatic expiration with cleanup
- Provider Validation: Verify OAuth responses with provider APIs
- Email Verification: Ensure email ownership through OAuth providers
- Account Isolation: UUID-based public identifiers protect real user IDs
Rate Limits
- OAuth attempts: 10 attempts per IP per hour
- Registration completion: 5 attempts per session per hour
- Account linking operations: 10 operations per user per hour
- Provider availability checks: Cached for 5 minutes
Connected Accounts Architecture
- UUID-Based Identity: Players are identified by UUIDs for privacy
- Currently Supported Providers: Only Google and Discord are fully implemented
- Primary Provider: One provider serves as the default for the account
- Account Linking: Users can connect both Google and Discord to one account
- Graceful Fallback: If primary provider fails, system can use secondary accounts
- Privacy Protection: Only necessary profile information is stored from OAuth providers
Implementation Notes
Provider Support Status
- Google: ✅ Fully implemented with OpenID Connect
- Discord: ✅ Fully implemented with standard OAuth 2.0
- Apple: ❌ Configuration exists but no endpoints implemented
- Slack: ❌ Configuration exists but no endpoints implemented
Session Management
- Sessions are stored in Cloudflare KV with 7-day TTL
- Session cookies are HttpOnly and secure in production
- Expired sessions are automatically cleaned up
- Players can have multiple active sessions
Database Integration
- Connected accounts are stored in
player_connected_accountstable - Player data is split across multiple normalized tables
- UUID-based foreign key relationships ensure data integrity
- Soft cascading deletes protect against accidental data loss
Future Provider Support
- Apple and Slack have OAuth configurations ready
- Implementation requires creating corresponding API endpoints:
/api/auth/appleand/api/auth/callback/apple/api/auth/slackand/api/auth/callback/slack
- Database constraints already support these providers
Migration Support
- Legacy provider-prefixed IDs are supported during transition
- Backward compatibility maintained for existing sessions
- Migration utilities available for seamless rollout