chore: archive simplify-authentik-auth change
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-05-18
|
||||
@@ -0,0 +1,128 @@
|
||||
# Simplified Authentik Auth Flow - Design
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
User → Frontend → Authentik (OAuth2) → Backend (Session) → Protected Resources
|
||||
```
|
||||
|
||||
## Authentication Flow
|
||||
|
||||
### 1. Login Initiation
|
||||
```
|
||||
GET /auth/login
|
||||
→ Redirect to Authentik OAuth authorize URL
|
||||
→ State parameter stored in cookie (auth_state)
|
||||
```
|
||||
|
||||
### 2. OAuth Callback
|
||||
```
|
||||
GET /auth/callback?code=...&state=...
|
||||
→ Verify state parameter
|
||||
→ Exchange code for access token with Authentik
|
||||
→ Fetch user info from Authentik /userinfo endpoint
|
||||
→ Create/update user in local database
|
||||
→ Create session cookie (signed, httpOnly)
|
||||
→ Redirect to frontend
|
||||
```
|
||||
|
||||
### 3. Authenticated Requests
|
||||
```
|
||||
Request with session cookie
|
||||
→ Verify session signature
|
||||
→ Load user from database
|
||||
→ Attach user to request context
|
||||
```
|
||||
|
||||
### 4. Logout
|
||||
```
|
||||
GET /auth/logout
|
||||
→ Delete session cookie
|
||||
→ Optionally revoke token at Authentik
|
||||
→ Redirect to frontend
|
||||
```
|
||||
|
||||
## Session Management
|
||||
|
||||
### Session Cookie
|
||||
- **Name**: `session`
|
||||
- **Value**: Signed cookie containing user_id
|
||||
- **Properties**: httpOnly, Secure (production), SameSite=Lax
|
||||
- **Expiry**: Browser session or configurable duration
|
||||
|
||||
### Session Store
|
||||
- In-memory or Redis (configurable)
|
||||
- Maps session_id → user_id + expiry
|
||||
- Simple cleanup on expiry
|
||||
|
||||
## User Sync
|
||||
|
||||
On each login:
|
||||
1. Fetch user info from Authentik `/application/o/userinfo/`
|
||||
2. Update local user record:
|
||||
- email
|
||||
- name
|
||||
- authentik_id
|
||||
- groups (for future team feature)
|
||||
3. Create user if not exists
|
||||
|
||||
## API Changes
|
||||
|
||||
### Removed Endpoints
|
||||
- `POST /auth/refresh` - No refresh tokens needed
|
||||
|
||||
### Modified Endpoints
|
||||
- `GET /auth/login` - Simpler, no nonce needed
|
||||
- `GET /auth/callback` - No JWT minting, just session creation
|
||||
- `GET /auth/me` - Return user from session instead of JWT
|
||||
- `POST /auth/logout` - Just clear session cookie
|
||||
|
||||
### New Endpoints
|
||||
- None (simplification!)
|
||||
|
||||
## Middleware Changes
|
||||
|
||||
### Current (to be removed)
|
||||
- JWT decoding
|
||||
- Token expiry checking
|
||||
- Refresh token validation
|
||||
|
||||
### New
|
||||
- Session cookie parsing
|
||||
- Signature verification
|
||||
- User loading from database
|
||||
|
||||
## Database Changes
|
||||
|
||||
### Remove Tables
|
||||
- `refresh_tokens` - No longer needed
|
||||
|
||||
### Keep Tables
|
||||
- `users` - Still needed for local user data
|
||||
- `user_configs` - User preferences
|
||||
|
||||
## Configuration Changes
|
||||
|
||||
### Removed
|
||||
- `JWT_SECRET`
|
||||
- `JWT_ALGORITHM`
|
||||
- `ACCESS_TOKEN_TTL_MINUTES`
|
||||
- `REFRESH_TOKEN_TTL_DAYS`
|
||||
|
||||
### Modified
|
||||
- `AUTHENTIK_AUDIENCE` - May not be needed
|
||||
|
||||
### Added
|
||||
- `SESSION_SECRET` - For signing session cookies
|
||||
- `SESSION_TTL_HOURS` - Session duration (default: 24)
|
||||
- `SESSION_STORE` - "memory" or "redis"
|
||||
|
||||
## Implementation Order
|
||||
|
||||
1. **Create session management module**
|
||||
2. **Simplify auth endpoints**
|
||||
3. **Update auth middleware**
|
||||
4. **Remove JWT and refresh token code**
|
||||
5. **Update frontend auth handling**
|
||||
6. **Update configuration**
|
||||
7. **Tests**
|
||||
@@ -0,0 +1,49 @@
|
||||
# Simplify Authentik Auth Flow
|
||||
|
||||
## Problem
|
||||
|
||||
The current authentication implementation is overly complex for our needs:
|
||||
|
||||
- **Multiple layers**: OIDC token exchange, refresh token rotation, complex cookie management
|
||||
- **Difficult to debug**: Many moving parts make deployment issues hard to diagnose
|
||||
- **Over-engineered**: We don't need the full OIDC flow complexity for our use case
|
||||
- **Maintenance burden**: The sophisticated approach requires deep understanding of OAuth2/OIDC internals
|
||||
|
||||
## Solution
|
||||
|
||||
Replace the current complex auth flow with a simplified approach:
|
||||
|
||||
1. **Authentik OAuth**: Keep OAuth2 authentication via Authentik
|
||||
2. **Session-based**: Use simple session cookies instead of JWT + refresh tokens
|
||||
3. **Authentik as source of truth**: User profiles synced from Authentik on login
|
||||
4. **Simpler implementation**: Reduce auth-related code by ~70%
|
||||
|
||||
## Benefits
|
||||
|
||||
- **Easier to deploy**: Fewer configuration variables and moving parts
|
||||
- **Easier to debug**: Clear flow: Login → Authentik → Session Cookie
|
||||
- **Less code**: Remove JWT service, refresh token store, complex OIDC logic
|
||||
- **Future-proof**: Still supports teams/groups via Authentik's user info endpoint
|
||||
- **Better UX**: No token refresh issues, simpler logout
|
||||
|
||||
## Scope
|
||||
|
||||
### What stays:
|
||||
- OAuth2 authentication via Authentik
|
||||
- User model in database (synced from Authentik)
|
||||
- Protected routes requiring authentication
|
||||
- Frontend auth state management
|
||||
|
||||
### What goes:
|
||||
- JWT access tokens
|
||||
- Refresh token rotation
|
||||
- Complex OIDC token verification
|
||||
- Multiple cookie types (access_token, refresh_token)
|
||||
- Token expiry/refresh logic
|
||||
- JWKS fetching and validation
|
||||
|
||||
### What's new:
|
||||
- Simple session cookie (httpOnly, secure, SameSite)
|
||||
- Authentik user info endpoint integration
|
||||
- Simplified auth middleware
|
||||
- Cleaner logout (just delete session)
|
||||
@@ -0,0 +1,114 @@
|
||||
# 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
|
||||
@@ -0,0 +1,76 @@
|
||||
# Simplify Authentik Auth - Tasks
|
||||
|
||||
## Phase 1: Remove Old Auth Code
|
||||
|
||||
- [ ] **Task 1.1**: Remove JWT service (`src/auth/jwt_service.py`)
|
||||
- Delete file
|
||||
- Remove all imports and usages
|
||||
|
||||
- [ ] **Task 1.2**: Remove refresh token store (`src/auth/refresh_store.py`)
|
||||
- Delete file
|
||||
- Remove refresh token model (`src/models/refresh_token.py`)
|
||||
- Remove table in Alembic migration
|
||||
|
||||
- [ ] **Task 1.3**: Remove complex OIDC logic
|
||||
- Simplify `src/auth/oidc.py` to basic OAuth2 flow
|
||||
- Remove JWKS fetching
|
||||
- Remove token verification
|
||||
|
||||
- [ ] **Task 1.4**: Clean up auth dependencies
|
||||
- Remove `python-jose` from dependencies if no longer needed
|
||||
- Update `pyproject.toml`
|
||||
|
||||
## Phase 2: Implement Session Auth
|
||||
|
||||
- [ ] **Task 2.1**: Create session service (`src/auth/session.py`)
|
||||
- Session cookie creation/signing
|
||||
- Session cookie parsing/verification
|
||||
- Session expiry handling
|
||||
|
||||
- [ ] **Task 2.2**: Update auth endpoints (`src/api/auth.py`)
|
||||
- Simplify login endpoint
|
||||
- Update callback to create session instead of JWT
|
||||
- Update /me to read from session
|
||||
- Simplify logout
|
||||
|
||||
- [ ] **Task 2.3**: Update auth middleware
|
||||
- Replace JWT middleware with session middleware
|
||||
- Load user from database based on session
|
||||
|
||||
- [ ] **Task 2.4**: Update configuration
|
||||
- Remove JWT config
|
||||
- Add SESSION_SECRET and SESSION_TTL_HOURS
|
||||
- Update .env.example
|
||||
- Update docker-compose configs
|
||||
|
||||
## Phase 3: Update Frontend
|
||||
|
||||
- [ ] **Task 3.1**: Remove JWT handling from frontend
|
||||
- Delete token refresh logic
|
||||
- Remove access token storage
|
||||
|
||||
- [ ] **Task 3.2**: Update auth API client
|
||||
- Remove refresh endpoint calls
|
||||
- Simplify auth state management
|
||||
|
||||
- [ ] **Task 3.3**: Update protected route logic
|
||||
- Check session cookie instead of JWT
|
||||
- Simpler auth state
|
||||
|
||||
## Phase 4: Testing & Cleanup
|
||||
|
||||
- [ ] **Task 4.1**: Update auth tests
|
||||
- Rewrite tests for new session-based flow
|
||||
- Remove JWT-specific tests
|
||||
- Add session validation tests
|
||||
|
||||
- [ ] **Task 4.2**: Run quality gates
|
||||
- ruff check
|
||||
- mypy
|
||||
- pytest
|
||||
- frontend typecheck + lint + build
|
||||
|
||||
- [ ] **Task 4.3**: Documentation
|
||||
- Update README with new auth flow
|
||||
- Update deployment docs
|
||||
- Document configuration changes
|
||||
Reference in New Issue
Block a user