225 lines
7.2 KiB
Markdown
225 lines
7.2 KiB
Markdown
# SSO (Single Sign-On) Implementation for Spotizerr
|
|
|
|
## Overview
|
|
|
|
I have successfully implemented comprehensive SSO backend logic for Google and GitHub authentication in your Spotizerr application. This implementation integrates seamlessly with your existing JWT-based authentication system.
|
|
|
|
## What Was Implemented
|
|
|
|
### 1. Dependencies Added
|
|
- Added `fastapi-sso==0.18.0` to `requirements.txt`
|
|
|
|
### 2. New Files Created
|
|
- `routes/auth/sso.py` - Complete SSO implementation with Google & GitHub support
|
|
- `routes/auth/sso_example.py` - Example client for testing SSO functionality
|
|
- `SSO_IMPLEMENTATION.md` - This documentation file
|
|
|
|
### 3. Updated Files
|
|
- `routes/auth/__init__.py` - Extended User model to support SSO fields
|
|
- `routes/auth/auth.py` - Updated authentication status to include SSO info
|
|
- `routes/auth/middleware.py` - Added SSO endpoints to public paths
|
|
- `AUTH_SETUP.md` - Comprehensive SSO setup documentation
|
|
- `requirements.txt` - Added fastapi-sso dependency
|
|
|
|
### 4. Extended User Model
|
|
The `User` class now supports:
|
|
- `sso_provider` - Which SSO provider was used (google/github)
|
|
- `sso_id` - Provider-specific user ID
|
|
- `is_sso_user` - Boolean flag for frontend use
|
|
|
|
## Environment Configuration
|
|
|
|
Create a `.env` file with the following variables:
|
|
|
|
```bash
|
|
# Basic Authentication
|
|
ENABLE_AUTH=true
|
|
JWT_SECRET=your-super-secret-jwt-key-change-in-production
|
|
JWT_EXPIRATION_HOURS=24
|
|
DEFAULT_ADMIN_USERNAME=admin
|
|
DEFAULT_ADMIN_PASSWORD=your-secure-password
|
|
|
|
# SSO Configuration
|
|
SSO_ENABLED=true
|
|
SSO_BASE_REDIRECT_URI=http://localhost:8000/api/auth/sso/callback
|
|
FRONTEND_URL=http://localhost:3000
|
|
|
|
# Google SSO (optional)
|
|
GOOGLE_CLIENT_ID=your-google-client-id
|
|
GOOGLE_CLIENT_SECRET=your-google-client-secret
|
|
|
|
# GitHub SSO (optional)
|
|
GITHUB_CLIENT_ID=your-github-client-id
|
|
GITHUB_CLIENT_SECRET=your-github-client-secret
|
|
```
|
|
|
|
## API Endpoints Added
|
|
|
|
### SSO Status & Information
|
|
- `GET /api/auth/sso/status` - Get SSO configuration and available providers
|
|
|
|
### Google SSO
|
|
- `GET /api/auth/sso/login/google` - Initiate Google OAuth flow
|
|
- `GET /api/auth/sso/callback/google` - Handle Google OAuth callback (automatic)
|
|
|
|
### GitHub SSO
|
|
- `GET /api/auth/sso/login/github` - Initiate GitHub OAuth flow
|
|
- `GET /api/auth/sso/callback/github` - Handle GitHub OAuth callback (automatic)
|
|
|
|
### SSO Management
|
|
- `POST /api/auth/sso/unlink/{provider}` - Unlink SSO provider from user account
|
|
|
|
### Enhanced Authentication Status
|
|
- `GET /api/auth/status` - Now includes SSO status and available providers
|
|
|
|
## OAuth Provider Setup
|
|
|
|
### Google SSO Setup
|
|
|
|
1. Go to [Google Cloud Console](https://console.cloud.google.com/)
|
|
2. Create a new project or select existing one
|
|
3. Enable Google+ API
|
|
4. Go to "Credentials" → "Create Credentials" → "OAuth 2.0 Client IDs"
|
|
5. Configure OAuth consent screen
|
|
6. Set authorized redirect URIs:
|
|
- Development: `http://localhost:8000/api/auth/sso/callback/google`
|
|
- Production: `https://yourdomain.com/api/auth/sso/callback/google`
|
|
7. Copy Client ID and Client Secret to environment variables
|
|
|
|
### GitHub SSO Setup
|
|
|
|
1. Go to GitHub Settings → Developer settings → OAuth Apps
|
|
2. Click "New OAuth App"
|
|
3. Fill in application details:
|
|
- Application name: Your app name
|
|
- Homepage URL: Your app URL
|
|
- Authorization callback URL:
|
|
- Development: `http://localhost:8000/api/auth/sso/callback/github`
|
|
- Production: `https://yourdomain.com/api/auth/sso/callback/github`
|
|
4. Copy Client ID and Client Secret to environment variables
|
|
|
|
## How It Works
|
|
|
|
### SSO Flow
|
|
1. User clicks "Login with Google/GitHub" button in frontend
|
|
2. Frontend redirects to `/api/auth/sso/login/{provider}`
|
|
3. User is redirected to provider's OAuth consent screen
|
|
4. After consent, provider redirects to `/api/auth/sso/callback/{provider}`
|
|
5. Backend validates OAuth code and retrieves user info
|
|
6. System creates or updates user account
|
|
7. JWT token is generated and set as HTTP-only cookie
|
|
8. User is redirected to frontend with authentication complete
|
|
|
|
### User Management
|
|
- **New SSO Users**: Automatically created with `user` role (first user gets `admin`)
|
|
- **Existing Users**: SSO provider linked to existing account by email
|
|
- **Username Generation**: Uses email prefix, ensures uniqueness
|
|
- **Password**: SSO users have `password_hash: null` (cannot use password login)
|
|
|
|
## Testing the Implementation
|
|
|
|
### 1. Install Dependencies
|
|
```bash
|
|
pip install fastapi-sso==0.18.0
|
|
```
|
|
|
|
### 2. Configure Environment
|
|
Set up your `.env` file with the OAuth credentials from Google/GitHub
|
|
|
|
### 3. Start the Application
|
|
```bash
|
|
uvicorn app:app --reload
|
|
```
|
|
|
|
### 4. Test SSO Status
|
|
```bash
|
|
curl http://localhost:8000/api/auth/sso/status
|
|
```
|
|
|
|
### 5. Test Authentication Flow
|
|
1. Visit `http://localhost:8000/api/auth/sso/login/google` in browser
|
|
2. Complete OAuth flow
|
|
3. Should redirect to frontend with authentication
|
|
|
|
### 6. Programmatic Testing
|
|
Run the example script:
|
|
```bash
|
|
python routes/auth/sso_example.py
|
|
```
|
|
|
|
## Security Features
|
|
|
|
### Production Ready
|
|
- **HTTPS Support**: Set `allow_insecure_http=False` in production
|
|
- **Secure Cookies**: HTTP-only cookies with secure flag
|
|
- **CORS Configuration**: Properly configured for your frontend domain
|
|
- **Token Validation**: Full server-side JWT validation
|
|
- **Provider Verification**: Validates OAuth responses from providers
|
|
|
|
### OAuth Security
|
|
- **State Parameter**: CSRF protection in OAuth flow
|
|
- **Redirect URI Validation**: Strict redirect URI matching
|
|
- **Token Expiration**: Configurable JWT token expiration
|
|
- **Provider Validation**: Ensures tokens come from legitimate providers
|
|
|
|
## Integration Points
|
|
|
|
### Frontend Integration
|
|
The authentication status endpoint now returns SSO information:
|
|
|
|
```json
|
|
{
|
|
"auth_enabled": true,
|
|
"sso_enabled": true,
|
|
"sso_providers": ["google", "github"],
|
|
"authenticated": false,
|
|
"user": null,
|
|
"registration_enabled": true
|
|
}
|
|
```
|
|
|
|
### User Data Structure
|
|
SSO users have additional fields:
|
|
|
|
```json
|
|
{
|
|
"username": "john_doe",
|
|
"email": "john@example.com",
|
|
"role": "user",
|
|
"sso_provider": "google",
|
|
"is_sso_user": true,
|
|
"created_at": "2024-01-15T10:30:00",
|
|
"last_login": "2024-01-15T10:30:00"
|
|
}
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
The implementation includes comprehensive error handling for:
|
|
- Missing OAuth credentials
|
|
- OAuth flow failures
|
|
- Provider-specific errors
|
|
- Invalid redirect URIs
|
|
- Network timeouts
|
|
- Invalid tokens
|
|
|
|
## Backwards Compatibility
|
|
|
|
- **Existing Users**: Unaffected, can still use password authentication
|
|
- **Existing API**: All existing endpoints work unchanged
|
|
- **Configuration**: SSO is optional, system works without it
|
|
- **Database**: Extends existing user storage, no migration needed
|
|
|
|
## Next Steps
|
|
|
|
1. **Configure OAuth Apps**: Set up Google and GitHub OAuth applications
|
|
2. **Update Frontend**: Add SSO login buttons that redirect to SSO endpoints
|
|
3. **Test Flow**: Test complete authentication flow end-to-end
|
|
4. **Production Setup**: Configure HTTPS and production redirect URIs
|
|
5. **User Management**: Add SSO management to your admin interface
|
|
|
|
## Support
|
|
|
|
The implementation follows FastAPI best practices and integrates cleanly with your existing authentication system. All SSO functionality is optional and gracefully degrades if not configured.
|
|
|
|
For issues or questions, check the comprehensive documentation in `AUTH_SETUP.md` or refer to the example client in `routes/auth/sso_example.py`. |