2ce7862058
Replace complex JWT + refresh token authentication with simple session-based auth using signed cookies. **Removed:** - JWT token service (jwt_service.py) - Refresh token store (refresh_store.py) - Refresh token model and database table - JWKS fetching and OIDC token verification - python-jose dependency **Added:** - Session service (session.py) with HMAC-SHA256 signed cookies - Auth dependencies module for shared auth logic - Session-based auth endpoints **Updated:** - All API endpoints to use session-based auth - Config: removed JWT settings, added SESSION_SECRET/SESSION_TTL_HOURS - Tests: rewritten for session-based flow - Frontend: no changes needed (already uses cookies) Quality gates: ruff ✓, mypy ✓, typecheck ✓, lint ✓
115 lines
2.8 KiB
Markdown
115 lines
2.8 KiB
Markdown
# Simplified Auth Flow Specification
|
|
|
|
## Requirements
|
|
|
|
### Functional Requirements
|
|
|
|
1. **OAuth2 Login**: Users authenticate via Authentik using standard OAuth2 flow
|
|
2. **Session Management**: Authenticated users have a signed session cookie
|
|
3. **User Sync**: User data (email, name, groups) synced from Authentik on login
|
|
4. **Protected Routes**: API endpoints can require authentication
|
|
5. **Logout**: Users can logout, clearing their session
|
|
|
|
### Non-Functional Requirements
|
|
|
|
1. **Simplicity**: Auth flow should be understandable in 5 minutes
|
|
2. **Security**: Session cookies must be signed and httpOnly
|
|
3. **Stateless**: No server-side session state (cookie contains all needed info)
|
|
4. **Performance**: No token refresh overhead
|
|
|
|
## API Specification
|
|
|
|
### GET /auth/login
|
|
Initiates OAuth2 login flow.
|
|
|
|
**Response**: 307 Redirect to Authentik authorize URL
|
|
|
|
### GET /auth/callback
|
|
Handles OAuth2 callback from Authentik.
|
|
|
|
**Query Parameters**:
|
|
- `code`: Authorization code
|
|
- `state`: State parameter for CSRF protection
|
|
|
|
**Response**:
|
|
- Success: 307 Redirect to frontend with session cookie set
|
|
- Error: 400 Bad Request (invalid state or code)
|
|
|
|
### GET /auth/me
|
|
Returns current authenticated user.
|
|
|
|
**Headers**: Requires session cookie
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"email": "user@example.com",
|
|
"name": "User Name",
|
|
"avatar_url": "..."
|
|
}
|
|
```
|
|
|
|
### POST /auth/logout
|
|
Logs out current user.
|
|
|
|
**Response**: 200 OK with session cookie cleared
|
|
|
|
## Data Model
|
|
|
|
### User Model (existing, kept)
|
|
```python
|
|
class User:
|
|
id: UUID
|
|
email: str
|
|
name: str
|
|
authentik_id: str
|
|
avatar_url: Optional[str]
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
```
|
|
|
|
### Session Cookie Format
|
|
```
|
|
session={signed_payload}; HttpOnly; Secure; SameSite=Lax
|
|
```
|
|
|
|
Where signed_payload is:
|
|
```json
|
|
{
|
|
"user_id": "uuid",
|
|
"exp": 1234567890
|
|
}
|
|
```
|
|
|
|
Signed with HMAC-SHA256 using SESSION_SECRET.
|
|
|
|
## Security Considerations
|
|
|
|
1. **CSRF Protection**: State parameter in OAuth flow
|
|
2. **Session Security**: Signed cookies prevent tampering
|
|
3. **Cookie Attributes**: httpOnly, Secure, SameSite=Lax
|
|
4. **Session Expiry**: Configurable TTL with automatic cleanup
|
|
5. **Token Handling**: Authentik access token not exposed to client
|
|
|
|
## Error Handling
|
|
|
|
### Authentication Errors
|
|
- Missing session: 401 Unauthorized
|
|
- Invalid session signature: 401 Unauthorized
|
|
- Expired session: 401 Unauthorized (redirect to login)
|
|
- Invalid OAuth state: 400 Bad Request
|
|
- OAuth code exchange failure: 400 Bad Request
|
|
|
|
## Future Considerations
|
|
|
|
### Teams/Groups
|
|
- Authentik groups available via userinfo endpoint
|
|
- Can store group membership in user model
|
|
- Team management can be built on top
|
|
|
|
### Session Persistence
|
|
- Currently using signed cookies (stateless)
|
|
- Can add Redis session store later if needed
|
|
- No database changes required for upgrade
|