feat: Add OIDC authentication with Authentik integration
- Add OIDC login flow with Authentik provider - Implement session-based auth with Redis store - Add avatar display from OIDC claims - Fix input field performance with react-textarea-autosize - Stabilize callbacks to prevent unnecessary re-renders - Fix history loading to skip empty session files - Add 2-row default height for input textarea 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
402
.prompts/001-oidc-auth-plan/SUMMARY.md
Normal file
402
.prompts/001-oidc-auth-plan/SUMMARY.md
Normal file
@@ -0,0 +1,402 @@
|
||||
# OIDC Authentication Implementation - Executive Summary
|
||||
|
||||
## Overview
|
||||
|
||||
This plan details the complete implementation of OIDC authentication for Claude Web UI using Authentik as the identity provider. The implementation adds secure, production-ready authentication with group-based access control while preserving the existing WebSocket architecture.
|
||||
|
||||
## Current State
|
||||
|
||||
**Backend:**
|
||||
- Single-file Express server (`backend/server.js`, 999 lines)
|
||||
- WebSocket-based Claude Code CLI interface
|
||||
- No authentication or authorization
|
||||
- In-memory session storage
|
||||
|
||||
**Frontend:**
|
||||
- React application with SessionContext for state management
|
||||
- Direct WebSocket connections
|
||||
- localStorage for session persistence
|
||||
- No authentication UI
|
||||
|
||||
## Target State
|
||||
|
||||
**Authentication:**
|
||||
- OIDC provider: Authentik (auth.sneakercloud.de)
|
||||
- Authorization flow: Authorization Code with PKCE
|
||||
- Token storage: httpOnly cookies (XSS-safe)
|
||||
- Session backend: Redis (persistent, scalable)
|
||||
|
||||
**Authorization:**
|
||||
- Groups: `agent-admin` (full access), `agent-users` (standard access)
|
||||
- Protected REST endpoints
|
||||
- Authenticated WebSocket connections
|
||||
- User-isolated sessions
|
||||
|
||||
## Implementation Approach
|
||||
|
||||
### 5 Phases, 11-16 Days
|
||||
|
||||
#### Phase 1: Foundation (2-3 days)
|
||||
- Configure Authentik OIDC Provider/Application
|
||||
- Refactor monolithic backend into modules
|
||||
- Add dependencies (express-session, openid-client, Redis)
|
||||
- Implement Redis session store
|
||||
|
||||
#### Phase 2: Authentication Flow (2-3 days)
|
||||
- Implement OIDC client wrapper
|
||||
- Create auth routes (login, callback, logout)
|
||||
- Configure secure session cookies
|
||||
- Handle token refresh
|
||||
|
||||
#### Phase 3: API Protection (2-3 days)
|
||||
- Create authentication middleware
|
||||
- Protect all REST endpoints
|
||||
- Secure WebSocket connections
|
||||
- Associate sessions with users
|
||||
|
||||
#### Phase 4: Frontend UI (3-4 days)
|
||||
- Create AuthContext for authentication state
|
||||
- Build login page component
|
||||
- Add protected route wrapper
|
||||
- Integrate with existing SessionContext
|
||||
- Add user menu/logout
|
||||
|
||||
#### Phase 5: Production Hardening (2-3 days)
|
||||
- Security enhancements (CSRF, rate limiting, CSP)
|
||||
- Logging and monitoring
|
||||
- Error handling and edge cases
|
||||
- Documentation
|
||||
- Testing
|
||||
|
||||
## Key Technical Decisions
|
||||
|
||||
### 1. Backend Refactoring
|
||||
**Decision:** Split monolithic `server.js` into modular structure
|
||||
|
||||
**Rationale:**
|
||||
- Improves maintainability
|
||||
- Separates concerns
|
||||
- Easier testing
|
||||
- Supports future growth
|
||||
|
||||
**Structure:**
|
||||
```
|
||||
backend/
|
||||
├── server.js # Entry point
|
||||
├── config/auth.js # Auth configuration
|
||||
├── middleware/ # Auth & session middleware
|
||||
├── routes/ # API, auth, WebSocket routes
|
||||
└── utils/ # OIDC client wrapper
|
||||
```
|
||||
|
||||
### 2. Session Storage
|
||||
**Decision:** Redis with express-session
|
||||
|
||||
**Rationale:**
|
||||
- Persistent across restarts
|
||||
- Scalable to multiple backend instances
|
||||
- Fast session lookups (<10ms)
|
||||
- Industry standard
|
||||
|
||||
**Alternative Considered:** In-memory sessions
|
||||
- **Rejected:** Lost on restart, not scalable
|
||||
|
||||
### 3. Token Storage
|
||||
**Decision:** httpOnly cookies with encrypted tokens in Redis
|
||||
|
||||
**Rationale:**
|
||||
- httpOnly prevents XSS attacks
|
||||
- Secure flag ensures HTTPS-only
|
||||
- sameSite=lax prevents CSRF
|
||||
- Encryption at rest protects Redis compromise
|
||||
|
||||
**Alternative Considered:** localStorage
|
||||
- **Rejected:** Vulnerable to XSS
|
||||
|
||||
### 4. WebSocket Authentication
|
||||
**Decision:** Cookie-based session validation on upgrade
|
||||
|
||||
**Rationale:**
|
||||
- Cookies automatically included in upgrade request
|
||||
- Consistent with REST API auth
|
||||
- No need for separate token mechanism
|
||||
|
||||
**Implementation:**
|
||||
- Parse cookies from upgrade request headers
|
||||
- Load session from Redis
|
||||
- Validate user before accepting connection
|
||||
- Reject upgrade with 1008 code if unauthorized
|
||||
|
||||
### 5. OIDC Library
|
||||
**Decision:** `openid-client` (certified OIDC client)
|
||||
|
||||
**Rationale:**
|
||||
- Official OpenID Foundation certified
|
||||
- Actively maintained
|
||||
- Built-in PKCE support
|
||||
- Automatic discovery
|
||||
|
||||
**Alternative Considered:** `passport-openidconnect`
|
||||
- **Rejected:** More complex, passport overhead not needed
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Authentication
|
||||
- Authorization Code flow with PKCE
|
||||
- State parameter for CSRF protection
|
||||
- Nonce validation in ID token
|
||||
- Token signature verification
|
||||
- HTTPS-only in production
|
||||
|
||||
### Session Management
|
||||
- httpOnly cookies (no JavaScript access)
|
||||
- Secure flag (HTTPS-only)
|
||||
- sameSite=lax (CSRF protection)
|
||||
- 24-hour expiry with refresh
|
||||
- Encrypted tokens at rest
|
||||
|
||||
### API Protection
|
||||
- All endpoints require authentication
|
||||
- Group-based authorization
|
||||
- Rate limiting on auth endpoints
|
||||
- Origin validation on WebSocket upgrade
|
||||
- Content Security Policy headers
|
||||
|
||||
### Token Handling
|
||||
- Access tokens encrypted in Redis
|
||||
- Refresh tokens encrypted in Redis
|
||||
- Auto-refresh 5 minutes before expiry
|
||||
- Tokens cleared on logout
|
||||
- No tokens in logs
|
||||
|
||||
## Group-Based Access Control
|
||||
|
||||
### agent-users (Standard Access)
|
||||
- View hosts and projects
|
||||
- Create and manage own Claude sessions
|
||||
- Upload files to own sessions
|
||||
- View own session history
|
||||
- Standard WebSocket access
|
||||
|
||||
### agent-admin (Full Access)
|
||||
- All `agent-users` permissions
|
||||
- View all users' sessions (future)
|
||||
- Access admin endpoints (future)
|
||||
- Modify system configuration (future)
|
||||
|
||||
**Note:** Initial implementation focuses on authentication and basic group enforcement. Fine-grained permissions can be expanded post-MVP.
|
||||
|
||||
## Integration Points
|
||||
|
||||
### Authentik Configuration
|
||||
```yaml
|
||||
Provider:
|
||||
Name: Claude Web UI
|
||||
Type: OAuth2/OIDC
|
||||
Client Type: Confidential
|
||||
Flow: Authorization Code
|
||||
Scopes: openid, profile, email, groups
|
||||
|
||||
Application:
|
||||
Name: Claude Web UI
|
||||
Provider: [linked]
|
||||
Launch URL: https://agents.sneakercloud.de
|
||||
Redirect URI: https://agents.sneakercloud.de/auth/callback
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
```bash
|
||||
# OIDC
|
||||
OIDC_ISSUER=https://auth.sneakercloud.de/application/o/claude-web-ui/
|
||||
OIDC_CLIENT_ID=<from_authentik>
|
||||
OIDC_CLIENT_SECRET=<from_authentik>
|
||||
OIDC_REDIRECT_URI=https://agents.sneakercloud.de/auth/callback
|
||||
|
||||
# Session
|
||||
SESSION_SECRET=<generate_32_bytes>
|
||||
SESSION_MAX_AGE=86400000 # 24 hours
|
||||
REDIS_URL=redis://redis:6379
|
||||
|
||||
# App
|
||||
NODE_ENV=production
|
||||
FRONTEND_URL=https://agents.sneakercloud.de
|
||||
```
|
||||
|
||||
### Docker Compose Updates
|
||||
- Add Redis service
|
||||
- Mount Redis volume for persistence
|
||||
- Add environment variables
|
||||
- Configure service dependencies
|
||||
|
||||
## Risk Assessment
|
||||
|
||||
### High Risk
|
||||
**WebSocket Authentication Complexity**
|
||||
- Mitigation: Thorough testing, fallback to polling
|
||||
- Contingency: Feature flag to disable auth temporarily
|
||||
|
||||
**Authentik Downtime**
|
||||
- Mitigation: Session caching, graceful degradation
|
||||
- Contingency: Allow continued use of valid sessions
|
||||
|
||||
**Session Store Failure (Redis)**
|
||||
- Mitigation: Redis persistence, backup strategy
|
||||
- Contingency: Fallback to in-memory (degraded mode)
|
||||
|
||||
### Medium Risk
|
||||
**Token Refresh Failures**
|
||||
- Mitigation: Retry logic, clear error messages
|
||||
- Contingency: Force re-login
|
||||
|
||||
**CORS/Cookie Issues**
|
||||
- Mitigation: Proper domain configuration, testing
|
||||
- Contingency: Documented troubleshooting steps
|
||||
|
||||
### Low Risk
|
||||
**Group Mapping Errors**
|
||||
- Mitigation: Default to `agent-users` if no groups
|
||||
- Contingency: Manual group assignment in Authentik
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Unit Tests
|
||||
- OIDC client wrapper
|
||||
- Authentication middleware
|
||||
- Session management functions
|
||||
|
||||
### Integration Tests
|
||||
- Full login flow
|
||||
- Token exchange
|
||||
- Session persistence
|
||||
- WebSocket authentication
|
||||
|
||||
### Manual Tests
|
||||
- Login/logout flow
|
||||
- Session refresh
|
||||
- Token expiry handling
|
||||
- Group-based access
|
||||
- Multiple concurrent users
|
||||
- Admin vs user permissions
|
||||
|
||||
### Security Tests
|
||||
- XSS prevention (httpOnly cookies)
|
||||
- CSRF protection
|
||||
- Unauthorized API access
|
||||
- Session hijacking attempts
|
||||
- Token replay attacks
|
||||
|
||||
## Rollback Plan
|
||||
|
||||
**Feature Flag:** `AUTH_ENABLED` environment variable
|
||||
|
||||
**Rollback Steps:**
|
||||
1. Set `AUTH_ENABLED=false`
|
||||
2. Restart backend service
|
||||
3. Authentication middleware skipped
|
||||
4. Frontend shows app without login
|
||||
5. Investigate and fix issues
|
||||
6. Re-enable with `AUTH_ENABLED=true`
|
||||
|
||||
**Data Preservation:**
|
||||
- Sessions stored in Redis persist
|
||||
- User data not lost
|
||||
- Can re-enable seamlessly
|
||||
|
||||
## Success Criteria
|
||||
|
||||
### Functional
|
||||
- [ ] Unauthenticated users cannot access app
|
||||
- [ ] Login redirects to Authentik and back successfully
|
||||
- [ ] WebSocket connections authenticated
|
||||
- [ ] Sessions persist across browser refresh
|
||||
- [ ] Logout clears session completely
|
||||
- [ ] Group-based access control enforced
|
||||
|
||||
### Performance
|
||||
- [ ] Auth middleware overhead <100ms
|
||||
- [ ] Session lookup <10ms
|
||||
- [ ] No WebSocket latency impact
|
||||
- [ ] Token refresh transparent to user
|
||||
|
||||
### Security
|
||||
- [ ] Zero XSS vulnerabilities
|
||||
- [ ] Zero unauthorized access
|
||||
- [ ] Tokens encrypted at rest
|
||||
- [ ] HTTPS-only in production
|
||||
- [ ] Rate limiting effective
|
||||
|
||||
### User Experience
|
||||
- [ ] Login flow <5 seconds
|
||||
- [ ] Clear error messages
|
||||
- [ ] No unnecessary re-authentication
|
||||
- [ ] Seamless session refresh
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
**Post-MVP Features:**
|
||||
- Multi-factor authentication via Authentik
|
||||
- API keys for CLI/programmatic access
|
||||
- Session management UI (view/revoke sessions)
|
||||
- Audit log for all actions
|
||||
- Fine-grained RBAC expansion
|
||||
- User preferences/settings storage
|
||||
- SSO with other internal services
|
||||
|
||||
## Dependencies
|
||||
|
||||
### NPM Packages
|
||||
- `express-session@^1.18.0` - Session management
|
||||
- `connect-redis@^7.1.0` - Redis session store
|
||||
- `redis@^4.6.0` - Redis client
|
||||
- `openid-client@^5.6.0` - OIDC client
|
||||
- `cookie-parser@^1.4.6` - Cookie parsing
|
||||
|
||||
### Infrastructure
|
||||
- Redis (session storage)
|
||||
- Authentik (identity provider)
|
||||
- Docker (containerization)
|
||||
|
||||
### External Services
|
||||
- Authentik @ auth.sneakercloud.de
|
||||
- Redis instance (new or existing)
|
||||
|
||||
## Documentation Deliverables
|
||||
|
||||
1. **AUTHENTICATION.md** - System overview and architecture
|
||||
2. **SETUP.md** - Step-by-step Authentik configuration
|
||||
3. **CONFIGURATION.md** - Environment variables reference
|
||||
4. **TROUBLESHOOTING.md** - Common issues and solutions
|
||||
5. **README.md** - Updated with authentication section
|
||||
|
||||
## Timeline Summary
|
||||
|
||||
| Phase | Duration | Key Deliverables |
|
||||
|-------|----------|------------------|
|
||||
| 1: Foundation | 2-3 days | Authentik setup, backend refactor, Redis |
|
||||
| 2: Auth Flow | 2-3 days | OIDC routes, token handling, callbacks |
|
||||
| 3: API Protection | 2-3 days | Middleware, protected endpoints, WebSocket auth |
|
||||
| 4: Frontend UI | 3-4 days | AuthContext, login page, user menu |
|
||||
| 5: Hardening | 2-3 days | Security, logging, testing, docs |
|
||||
| **Total** | **11-16 days** | Production-ready OIDC authentication |
|
||||
|
||||
## Approval & Next Steps
|
||||
|
||||
**This Plan:**
|
||||
- Provides complete roadmap for OIDC implementation
|
||||
- Addresses all security requirements
|
||||
- Maintains existing functionality
|
||||
- Enables phased rollout
|
||||
- Includes rollback strategy
|
||||
|
||||
**Next Steps:**
|
||||
1. Review and approve plan
|
||||
2. Set up Authentik provider/application
|
||||
3. Begin Phase 1 implementation
|
||||
4. Schedule checkpoints after each phase
|
||||
5. Plan production deployment
|
||||
|
||||
**Questions/Concerns:**
|
||||
- Authentik already configured or needs setup?
|
||||
- Redis instance available or needs provisioning?
|
||||
- Preferred timeline/priority adjustments?
|
||||
- Additional requirements or constraints?
|
||||
253
.prompts/001-oidc-auth-plan/completed/001-oidc-auth-plan.md
Normal file
253
.prompts/001-oidc-auth-plan/completed/001-oidc-auth-plan.md
Normal file
@@ -0,0 +1,253 @@
|
||||
<objective>
|
||||
Create an implementation roadmap for OIDC authentication with Authentik for Claude Web UI.
|
||||
|
||||
Purpose: Guide phased implementation of OIDC authentication with clear milestones
|
||||
Input: Current codebase structure, Authentik configuration requirements
|
||||
Output: oidc-auth-plan.md with 4-5 implementation phases
|
||||
</objective>
|
||||
|
||||
<context>
|
||||
Project: Claude Web UI - Web interface for Claude Code CLI
|
||||
URL: https://agents.sneakercloud.de
|
||||
Stack:
|
||||
- Backend: Node.js/Express (server.js) with WebSocket
|
||||
- Frontend: React/Vite with JSX components
|
||||
- Auth Provider: Authentik (https://auth.sneakercloud.de)
|
||||
|
||||
Current backend structure:
|
||||
- Single file: backend/server.js (~999 lines)
|
||||
- Express app with CORS, WebSocket server
|
||||
- No authentication currently implemented
|
||||
- REST endpoints: /api/hosts, /api/projects, /api/health, /api/browse, /api/upload, /api/history
|
||||
|
||||
Current frontend structure:
|
||||
- src/App.jsx - Main application
|
||||
- src/contexts/SessionContext.jsx - Session state management
|
||||
- src/hooks/useClaudeSession.js - WebSocket connection hook
|
||||
- src/components/ - UI components (ChatPanel, Sidebar, Header, etc.)
|
||||
|
||||
Authentication requirements:
|
||||
- OIDC Provider: Authentik
|
||||
- Auth Flow: Redirect Flow (Authorization Code)
|
||||
- Token Storage: httpOnly Cookies (XSS-safe)
|
||||
- Groups: agent-admin (full access), agent-users (standard access)
|
||||
- Session Duration: Configurable, with refresh token support
|
||||
</context>
|
||||
|
||||
<planning_requirements>
|
||||
Requirements to address:
|
||||
1. Authentik OIDC Application setup (Provider + Application)
|
||||
2. Backend OIDC middleware with session management
|
||||
3. Frontend AuthContext with login/logout flow
|
||||
4. Protected routes and API endpoints
|
||||
5. Group-based access control (admin vs users)
|
||||
6. httpOnly cookie-based token storage
|
||||
|
||||
Constraints:
|
||||
- Must work with existing WebSocket architecture
|
||||
- Minimal changes to existing components
|
||||
- Single-file backend (server.js) - consider refactoring into modules
|
||||
- Production-ready security (no localStorage tokens)
|
||||
|
||||
Success criteria:
|
||||
- Unauthenticated users see login page
|
||||
- Login redirects to Authentik, returns with session
|
||||
- WebSocket connections are authenticated
|
||||
- API endpoints check authentication
|
||||
- Admin users have additional capabilities
|
||||
- Sessions persist across browser refresh
|
||||
</planning_requirements>
|
||||
|
||||
<output_structure>
|
||||
Save to: `.prompts/001-oidc-auth-plan/oidc-auth-plan.md`
|
||||
|
||||
Structure the plan using this XML format:
|
||||
|
||||
```xml
|
||||
<plan>
|
||||
<summary>
|
||||
{One paragraph overview of the OIDC implementation approach}
|
||||
</summary>
|
||||
|
||||
<phases>
|
||||
<phase number="1" name="authentik-setup">
|
||||
<objective>Create OIDC Provider and Application in Authentik</objective>
|
||||
<tasks>
|
||||
<task priority="high">Create OAuth2/OIDC Provider in Authentik</task>
|
||||
<task priority="high">Configure redirect URIs for agents.sneakercloud.de</task>
|
||||
<task priority="high">Create Application and bind to Provider</task>
|
||||
<task priority="medium">Create groups: agent-admin, agent-users</task>
|
||||
<task priority="medium">Configure group claims in OIDC scope</task>
|
||||
</tasks>
|
||||
<deliverables>
|
||||
<deliverable>Authentik OIDC app configured</deliverable>
|
||||
<deliverable>Client ID and Secret generated</deliverable>
|
||||
<deliverable>Groups created and mapped</deliverable>
|
||||
</deliverables>
|
||||
<dependencies>Admin access to Authentik</dependencies>
|
||||
<execution_notes>
|
||||
Document the exact Authentik configuration steps.
|
||||
Save Client ID/Secret to .env (not committed).
|
||||
Test OIDC endpoints manually before proceeding.
|
||||
</execution_notes>
|
||||
</phase>
|
||||
|
||||
<phase number="2" name="backend-auth-module">
|
||||
<objective>Implement OIDC authentication in backend</objective>
|
||||
<tasks>
|
||||
<task priority="high">Install dependencies: openid-client, cookie-parser, express-session</task>
|
||||
<task priority="high">Create auth module with OIDC client configuration</task>
|
||||
<task priority="high">Implement /api/auth/login - redirect to Authentik</task>
|
||||
<task priority="high">Implement /api/auth/callback - handle OIDC response</task>
|
||||
<task priority="high">Implement /api/auth/logout - clear session</task>
|
||||
<task priority="medium">Implement /api/auth/me - return current user info</task>
|
||||
<task priority="medium">Create auth middleware for protected routes</task>
|
||||
<task priority="medium">Add session validation to WebSocket connections</task>
|
||||
</tasks>
|
||||
<deliverables>
|
||||
<deliverable>backend/auth.js module</deliverable>
|
||||
<deliverable>Session-based authentication with httpOnly cookies</deliverable>
|
||||
<deliverable>Protected API routes</deliverable>
|
||||
</deliverables>
|
||||
<dependencies>Phase 1 complete (Authentik configured)</dependencies>
|
||||
<execution_notes>
|
||||
Use openid-client for OIDC implementation.
|
||||
Store session in memory initially (can add Redis later).
|
||||
Validate ID tokens and extract user info.
|
||||
Pass user context to WebSocket sessions.
|
||||
</execution_notes>
|
||||
</phase>
|
||||
|
||||
<phase number="3" name="frontend-auth-context">
|
||||
<objective>Implement React authentication context and UI</objective>
|
||||
<tasks>
|
||||
<task priority="high">Create AuthContext with user state management</task>
|
||||
<task priority="high">Create useAuth hook for components</task>
|
||||
<task priority="high">Create LoginPage component</task>
|
||||
<task priority="high">Implement protected route wrapper</task>
|
||||
<task priority="medium">Add login/logout buttons to Header</task>
|
||||
<task priority="medium">Show user info in UI</task>
|
||||
<task priority="low">Add loading state during auth check</task>
|
||||
</tasks>
|
||||
<deliverables>
|
||||
<deliverable>src/contexts/AuthContext.jsx</deliverable>
|
||||
<deliverable>src/hooks/useAuth.js</deliverable>
|
||||
<deliverable>src/components/LoginPage.jsx</deliverable>
|
||||
<deliverable>src/components/ProtectedRoute.jsx</deliverable>
|
||||
</deliverables>
|
||||
<dependencies>Phase 2 complete (backend auth working)</dependencies>
|
||||
<execution_notes>
|
||||
Check /api/auth/me on app load to determine auth state.
|
||||
Redirect to login page if not authenticated.
|
||||
After login, redirect back to original URL.
|
||||
Handle auth errors gracefully.
|
||||
</execution_notes>
|
||||
</phase>
|
||||
|
||||
<phase number="4" name="group-permissions">
|
||||
<objective>Implement group-based access control</objective>
|
||||
<tasks>
|
||||
<task priority="high">Extract groups from OIDC claims in backend</task>
|
||||
<task priority="high">Add isAdmin flag to user context</task>
|
||||
<task priority="medium">Protect admin-only API routes</task>
|
||||
<task priority="medium">Show admin UI elements conditionally</task>
|
||||
<task priority="low">Add user management UI for admins (future)</task>
|
||||
</tasks>
|
||||
<deliverables>
|
||||
<deliverable>Group-based route protection</deliverable>
|
||||
<deliverable>Admin-specific UI elements</deliverable>
|
||||
</deliverables>
|
||||
<dependencies>Phase 3 complete</dependencies>
|
||||
<execution_notes>
|
||||
agent-admin: Full access, all hosts, all features
|
||||
agent-users: Limited hosts, standard features
|
||||
Check group membership on backend, pass to frontend.
|
||||
</execution_notes>
|
||||
</phase>
|
||||
|
||||
<phase number="5" name="testing-polish">
|
||||
<objective>Test, document, and polish the implementation</objective>
|
||||
<tasks>
|
||||
<task priority="high">Test full auth flow end-to-end</task>
|
||||
<task priority="high">Test WebSocket reconnection after session refresh</task>
|
||||
<task priority="medium">Handle edge cases (expired sessions, revoked tokens)</task>
|
||||
<task priority="medium">Update BookStack documentation</task>
|
||||
<task priority="low">Add session timeout warnings</task>
|
||||
</tasks>
|
||||
<deliverables>
|
||||
<deliverable>Working OIDC authentication</deliverable>
|
||||
<deliverable>Updated documentation</deliverable>
|
||||
</deliverables>
|
||||
<dependencies>Phase 4 complete</dependencies>
|
||||
</phase>
|
||||
</phases>
|
||||
|
||||
<metadata>
|
||||
<confidence level="high">
|
||||
OIDC with Authentik is well-documented pattern.
|
||||
httpOnly cookies with redirect flow is industry standard.
|
||||
openid-client is mature library for Node.js.
|
||||
</confidence>
|
||||
<dependencies>
|
||||
- Authentik admin access
|
||||
- DNS/SSL already configured (agents.sneakercloud.de)
|
||||
- Current app deployed and working
|
||||
</dependencies>
|
||||
<open_questions>
|
||||
- Session storage: In-memory vs Redis?
|
||||
- Token refresh strategy: Silent refresh vs re-login?
|
||||
- Should WebSocket auth use same session or separate token?
|
||||
</open_questions>
|
||||
<assumptions>
|
||||
- Authentik is accessible at auth.sneakercloud.de
|
||||
- User has admin access to create OIDC app
|
||||
- Current backend can be extended (single server.js file)
|
||||
- Frontend can add new components without major refactoring
|
||||
</assumptions>
|
||||
</metadata>
|
||||
</plan>
|
||||
```
|
||||
</output_structure>
|
||||
|
||||
<summary_requirements>
|
||||
Create `.prompts/001-oidc-auth-plan/SUMMARY.md`
|
||||
|
||||
Structure:
|
||||
```markdown
|
||||
# OIDC Auth Plan Summary
|
||||
|
||||
**{Substantive one-liner describing the plan}**
|
||||
|
||||
## Version
|
||||
v1
|
||||
|
||||
## Key Findings
|
||||
- {Phase 1 objective}
|
||||
- {Phase 2 objective}
|
||||
- {Phase 3 objective}
|
||||
- {Key architectural decision}
|
||||
|
||||
## Decisions Needed
|
||||
{Specific decisions requiring user input}
|
||||
|
||||
## Blockers
|
||||
{External impediments, or "None"}
|
||||
|
||||
## Next Step
|
||||
{Concrete forward action - likely "Execute Phase 1"}
|
||||
|
||||
---
|
||||
*Confidence: High*
|
||||
*Full output: oidc-auth-plan.md*
|
||||
```
|
||||
</summary_requirements>
|
||||
|
||||
<success_criteria>
|
||||
- Plan addresses all 5 requirements (Authentik, backend, frontend, routes, groups)
|
||||
- Phases are sequential and logically ordered
|
||||
- Each phase builds on previous deliverables
|
||||
- Tasks are specific and actionable
|
||||
- Metadata captures open questions and assumptions
|
||||
- SUMMARY.md created with phase overview
|
||||
- Ready for implementation prompts to consume
|
||||
</success_criteria>
|
||||
766
.prompts/001-oidc-auth-plan/oidc-auth-plan.md
Normal file
766
.prompts/001-oidc-auth-plan/oidc-auth-plan.md
Normal file
@@ -0,0 +1,766 @@
|
||||
# OIDC Authentication Implementation Plan for Claude Web UI
|
||||
|
||||
## Project Overview
|
||||
|
||||
**Project:** Claude Web UI - Web interface for Claude Code CLI
|
||||
**URL:** https://agents.sneakercloud.de
|
||||
**Auth Provider:** Authentik (https://auth.sneakercloud.de)
|
||||
**Implementation Goal:** Add production-ready OIDC authentication with group-based access control
|
||||
|
||||
## Current Architecture Analysis
|
||||
|
||||
### Backend (Node.js/Express)
|
||||
- **File:** `backend/server.js` (999 lines)
|
||||
- **Framework:** Express with WebSocket (ws library)
|
||||
- **Current State:** No authentication
|
||||
- **Endpoints:**
|
||||
- REST: `/api/hosts`, `/api/projects`, `/api/health`, `/api/browse`, `/api/upload/:sessionId`, `/api/history/:project`
|
||||
- WebSocket: Single endpoint on root path
|
||||
- **Sessions:** In-memory Map with UUIDs, no user association
|
||||
|
||||
### Frontend (React/Vite)
|
||||
- **Main:** `frontend/src/App.jsx` - Application shell
|
||||
- **State:** `frontend/src/contexts/SessionContext.jsx` - Session management via React Context
|
||||
- **WebSocket:** Direct connections stored in refs
|
||||
- **Storage:** localStorage for session persistence
|
||||
- **Current State:** No authentication UI or logic
|
||||
|
||||
### Key Constraints
|
||||
1. Single-file backend (consider modular refactoring)
|
||||
2. WebSocket architecture must be preserved
|
||||
3. No localStorage for tokens (XSS risk)
|
||||
4. Production security requirements
|
||||
5. Group-based access control needed
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Authentik Configuration & Backend Foundation
|
||||
|
||||
### Objectives
|
||||
- Configure Authentik OIDC Provider and Application
|
||||
- Refactor backend into modular structure
|
||||
- Add core authentication dependencies
|
||||
- Implement session storage mechanism
|
||||
|
||||
### Tasks
|
||||
|
||||
#### 1.1 Authentik Setup
|
||||
**Provider Configuration:**
|
||||
```yaml
|
||||
Name: Claude Web UI
|
||||
Client Type: Confidential
|
||||
Authorization Flow: Authorization Code
|
||||
Redirect URIs:
|
||||
- https://agents.sneakercloud.de/auth/callback
|
||||
- http://localhost:5173/auth/callback (dev)
|
||||
Scopes: openid, profile, email, groups
|
||||
```
|
||||
|
||||
**Application Configuration:**
|
||||
```yaml
|
||||
Name: Claude Web UI
|
||||
Provider: [linked to above]
|
||||
Launch URL: https://agents.sneakercloud.de
|
||||
```
|
||||
|
||||
**Group Mappings:**
|
||||
- Create groups: `agent-admin`, `agent-users`
|
||||
- Configure scope mappings to include groups in ID token
|
||||
- Test with user accounts
|
||||
|
||||
**Deliverables:**
|
||||
- Client ID and Client Secret
|
||||
- Discovery URL: `https://auth.sneakercloud.de/application/o/claude-web-ui/.well-known/openid-configuration`
|
||||
- Documented group structure
|
||||
|
||||
#### 1.2 Backend Refactoring
|
||||
**Current:** Single `backend/server.js` (999 lines)
|
||||
|
||||
**New Structure:**
|
||||
```
|
||||
backend/
|
||||
├── server.js # Main entry, app initialization
|
||||
├── config/
|
||||
│ └── auth.js # Auth config from env
|
||||
├── middleware/
|
||||
│ ├── auth.js # Authentication middleware
|
||||
│ └── session.js # Session management
|
||||
├── routes/
|
||||
│ ├── api.js # Existing API routes
|
||||
│ ├── auth.js # OIDC auth routes
|
||||
│ └── websocket.js # WebSocket handler
|
||||
└── utils/
|
||||
└── oidc.js # OIDC client wrapper
|
||||
```
|
||||
|
||||
**Migration Strategy:**
|
||||
1. Create new file structure
|
||||
2. Extract route handlers into modules
|
||||
3. Extract WebSocket logic
|
||||
4. Update server.js to import modules
|
||||
5. Test that existing functionality works
|
||||
|
||||
#### 1.3 Dependencies
|
||||
**Add to `backend/package.json`:**
|
||||
```json
|
||||
{
|
||||
"express-session": "^1.18.0",
|
||||
"connect-redis": "^7.1.0",
|
||||
"redis": "^4.6.0",
|
||||
"openid-client": "^5.6.0",
|
||||
"cookie-parser": "^1.4.6"
|
||||
}
|
||||
```
|
||||
|
||||
**Rationale:**
|
||||
- `express-session`: Session management
|
||||
- `connect-redis`: Session store (persistent, production-ready)
|
||||
- `redis`: Session backend
|
||||
- `openid-client`: Official OIDC client (certified)
|
||||
- `cookie-parser`: Cookie handling
|
||||
|
||||
#### 1.4 Session Storage
|
||||
**Redis Configuration:**
|
||||
- Use existing Redis instance or add to docker-compose
|
||||
- Configure session store with httpOnly cookies
|
||||
- Session TTL: 24 hours (configurable)
|
||||
- Secure flag in production
|
||||
|
||||
**Session Schema:**
|
||||
```javascript
|
||||
{
|
||||
sessionId: "uuid",
|
||||
userId: "oidc-sub",
|
||||
email: "user@example.com",
|
||||
name: "User Name",
|
||||
groups: ["agent-users"],
|
||||
accessToken: "encrypted",
|
||||
refreshToken: "encrypted",
|
||||
expiresAt: timestamp,
|
||||
createdAt: timestamp
|
||||
}
|
||||
```
|
||||
|
||||
### Verification Criteria
|
||||
- [ ] Authentik provider and application created
|
||||
- [ ] Test user can authenticate via Authentik UI
|
||||
- [ ] Backend refactored, all tests pass
|
||||
- [ ] Dependencies installed
|
||||
- [ ] Redis session store connected
|
||||
- [ ] Session CRUD operations working
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: OIDC Authentication Flow
|
||||
|
||||
### Objectives
|
||||
- Implement authorization code flow
|
||||
- Create auth routes (login, callback, logout)
|
||||
- Secure session cookies
|
||||
- Handle token refresh
|
||||
|
||||
### Tasks
|
||||
|
||||
#### 2.1 OIDC Client Setup
|
||||
**File:** `backend/utils/oidc.js`
|
||||
|
||||
**Functionality:**
|
||||
- Discover OIDC configuration from Authentik
|
||||
- Initialize Issuer and Client
|
||||
- Generate authorization URL
|
||||
- Handle token exchange
|
||||
- Validate ID tokens
|
||||
- Refresh access tokens
|
||||
|
||||
**Configuration (from env):**
|
||||
```bash
|
||||
OIDC_ISSUER=https://auth.sneakercloud.de/application/o/claude-web-ui/
|
||||
OIDC_CLIENT_ID=<from_authentik>
|
||||
OIDC_CLIENT_SECRET=<from_authentik>
|
||||
OIDC_REDIRECT_URI=https://agents.sneakercloud.de/auth/callback
|
||||
SESSION_SECRET=<generate_with_openssl>
|
||||
REDIS_URL=redis://localhost:6379
|
||||
```
|
||||
|
||||
#### 2.2 Authentication Routes
|
||||
**File:** `backend/routes/auth.js`
|
||||
|
||||
**Routes:**
|
||||
|
||||
**GET `/auth/login`**
|
||||
- Generate OIDC authorization URL with PKCE
|
||||
- Store state and nonce in session
|
||||
- Redirect to Authentik
|
||||
|
||||
**GET `/auth/callback`**
|
||||
- Validate state parameter
|
||||
- Exchange authorization code for tokens
|
||||
- Validate ID token signature and claims
|
||||
- Extract user info and groups
|
||||
- Create session with user data
|
||||
- Redirect to frontend (`/`)
|
||||
|
||||
**POST `/auth/logout`**
|
||||
- Destroy session
|
||||
- Optionally redirect to Authentik logout
|
||||
- Clear cookies
|
||||
|
||||
**GET `/auth/user`**
|
||||
- Return current user info from session
|
||||
- Return 401 if not authenticated
|
||||
|
||||
**POST `/auth/refresh`**
|
||||
- Use refresh token to get new access token
|
||||
- Update session
|
||||
- Return success/failure
|
||||
|
||||
#### 2.3 Session Cookie Configuration
|
||||
```javascript
|
||||
{
|
||||
name: 'claude.sid',
|
||||
secret: process.env.SESSION_SECRET,
|
||||
resave: false,
|
||||
saveUninitialized: false,
|
||||
cookie: {
|
||||
httpOnly: true, // No JavaScript access
|
||||
secure: true, // HTTPS only in production
|
||||
sameSite: 'lax', // CSRF protection
|
||||
maxAge: 24 * 60 * 60 * 1000 // 24 hours
|
||||
},
|
||||
store: redisStore // Redis session store
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.4 Token Management
|
||||
- Store access token in Redis session (encrypted)
|
||||
- Store refresh token in Redis session (encrypted)
|
||||
- Implement token refresh 5 minutes before expiry
|
||||
- Handle refresh failures (force re-login)
|
||||
|
||||
### Verification Criteria
|
||||
- [ ] Login redirects to Authentik
|
||||
- [ ] Callback successfully exchanges code for tokens
|
||||
- [ ] ID token validated and parsed
|
||||
- [ ] Groups extracted from token
|
||||
- [ ] Session created in Redis
|
||||
- [ ] Cookie set with correct flags
|
||||
- [ ] `/auth/user` returns user info
|
||||
- [ ] Logout destroys session
|
||||
- [ ] Token refresh works
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: Backend API Protection
|
||||
|
||||
### Objectives
|
||||
- Protect all API endpoints with authentication
|
||||
- Secure WebSocket connections
|
||||
- Implement group-based authorization
|
||||
- Handle unauthorized access gracefully
|
||||
|
||||
### Tasks
|
||||
|
||||
#### 3.1 Authentication Middleware
|
||||
**File:** `backend/middleware/auth.js`
|
||||
|
||||
**Middleware Functions:**
|
||||
|
||||
**`requireAuth`**
|
||||
- Check if session exists and is valid
|
||||
- Verify session in Redis
|
||||
- Attach `req.user` with user data
|
||||
- Return 401 if not authenticated
|
||||
|
||||
**`requireGroup(groups)`**
|
||||
- Check if `req.user.groups` includes required group
|
||||
- Return 403 if insufficient permissions
|
||||
- Usage: `requireGroup(['agent-admin'])`
|
||||
|
||||
**`optionalAuth`**
|
||||
- Attach user if authenticated
|
||||
- Continue if not authenticated
|
||||
- For endpoints that support both modes
|
||||
|
||||
#### 3.2 Protect REST Endpoints
|
||||
**Apply Middleware:**
|
||||
```javascript
|
||||
// All API routes require auth
|
||||
app.use('/api', requireAuth);
|
||||
|
||||
// Admin-only endpoints
|
||||
app.get('/api/admin/*', requireGroup(['agent-admin']));
|
||||
|
||||
// Health check remains public
|
||||
app.get('/api/health', (req, res) => ...);
|
||||
```
|
||||
|
||||
**Protected Endpoints:**
|
||||
- `/api/hosts` - Read: agent-users, Write: agent-admin
|
||||
- `/api/projects` - Read: agent-users
|
||||
- `/api/browse` - agent-users
|
||||
- `/api/upload/:sessionId` - agent-users
|
||||
- `/api/history/:project` - agent-users (own history only)
|
||||
|
||||
#### 3.3 WebSocket Authentication
|
||||
**Challenge:** WebSocket upgrade happens before HTTP middleware
|
||||
|
||||
**Solution: Cookie-based Auth**
|
||||
1. Parse cookies from upgrade request
|
||||
2. Load session from Redis
|
||||
3. Validate session
|
||||
4. Attach user to WebSocket connection
|
||||
5. Reject upgrade if not authenticated
|
||||
|
||||
**Implementation:**
|
||||
```javascript
|
||||
wss.on('connection', async (ws, req) => {
|
||||
// Parse cookies from req.headers.cookie
|
||||
// Load session from Redis
|
||||
// Validate user
|
||||
if (!user) {
|
||||
ws.close(1008, 'Unauthorized');
|
||||
return;
|
||||
}
|
||||
|
||||
// Attach user to connection
|
||||
ws.user = user;
|
||||
|
||||
// Continue with Claude session logic
|
||||
});
|
||||
```
|
||||
|
||||
#### 3.4 Session Association
|
||||
**Current:** Sessions stored by UUID, no user association
|
||||
|
||||
**New:**
|
||||
- Associate Claude sessions with authenticated user
|
||||
- Store user ID in session metadata
|
||||
- Allow users to only access their own sessions
|
||||
- Admin users can view all sessions (optional)
|
||||
|
||||
**Session Schema Update:**
|
||||
```javascript
|
||||
{
|
||||
sessionId: "uuid",
|
||||
userId: "oidc-sub", // NEW
|
||||
userEmail: "user@example.com", // NEW
|
||||
project: "/path/to/project",
|
||||
host: "neko",
|
||||
// ... existing fields
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.5 Error Handling
|
||||
- 401 Unauthorized: Not authenticated
|
||||
- 403 Forbidden: Insufficient permissions
|
||||
- Redirect to `/auth/login` for API calls
|
||||
- WebSocket: Close with error code
|
||||
- Frontend: Display login prompt
|
||||
|
||||
### Verification Criteria
|
||||
- [ ] Unauthenticated API calls return 401
|
||||
- [ ] WebSocket upgrades require valid session
|
||||
- [ ] Group-based access control works
|
||||
- [ ] Admin users have extended permissions
|
||||
- [ ] Sessions isolated by user
|
||||
- [ ] Error responses are clear
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: Frontend Authentication UI
|
||||
|
||||
### Objectives
|
||||
- Create AuthContext for authentication state
|
||||
- Implement login/logout UI
|
||||
- Add protected routes
|
||||
- Handle authentication errors
|
||||
- Integrate with existing SessionContext
|
||||
|
||||
### Tasks
|
||||
|
||||
#### 4.1 AuthContext
|
||||
**File:** `frontend/src/contexts/AuthContext.jsx`
|
||||
|
||||
**State:**
|
||||
```javascript
|
||||
{
|
||||
user: null | {
|
||||
id: string,
|
||||
email: string,
|
||||
name: string,
|
||||
groups: string[]
|
||||
},
|
||||
isLoading: boolean,
|
||||
error: string | null
|
||||
}
|
||||
```
|
||||
|
||||
**Methods:**
|
||||
- `login()` - Redirect to `/auth/login`
|
||||
- `logout()` - Call `/auth/logout`, clear state
|
||||
- `refreshUser()` - Call `/auth/user` to get current user
|
||||
- `checkAuth()` - Verify authentication on mount
|
||||
|
||||
**Auto-refresh:**
|
||||
- Poll `/auth/user` every 5 minutes
|
||||
- Handle 401 by redirecting to login
|
||||
- Update user state on success
|
||||
|
||||
#### 4.2 Login Flow
|
||||
**Current:** App loads directly to ChatPanel
|
||||
|
||||
**New:**
|
||||
1. App mounts
|
||||
2. AuthContext checks `/auth/user`
|
||||
3. If 401: Show login page
|
||||
4. If 200: Show app
|
||||
5. User clicks "Login with Authentik"
|
||||
6. Redirect to `/auth/login`
|
||||
7. Authentik authentication
|
||||
8. Callback redirects to `/`
|
||||
9. AuthContext refreshes user
|
||||
10. App shows
|
||||
|
||||
#### 4.3 Login Page Component
|
||||
**File:** `frontend/src/components/LoginPage.jsx`
|
||||
|
||||
**UI:**
|
||||
- Centered card
|
||||
- Claude Web UI branding
|
||||
- "Login with Authentik" button
|
||||
- Loading state during redirect
|
||||
- Error messages
|
||||
|
||||
**Design:**
|
||||
- Match existing dark theme
|
||||
- Simple, professional
|
||||
- No local credentials (OIDC only)
|
||||
|
||||
#### 4.4 Protected App Wrapper
|
||||
**File:** `frontend/src/App.jsx` (update)
|
||||
|
||||
**Logic:**
|
||||
```javascript
|
||||
function App() {
|
||||
return (
|
||||
<AuthProvider>
|
||||
<AuthenticatedApp />
|
||||
</AuthProvider>
|
||||
);
|
||||
}
|
||||
|
||||
function AuthenticatedApp() {
|
||||
const { user, isLoading } = useAuth();
|
||||
|
||||
if (isLoading) return <LoadingSpinner />;
|
||||
if (!user) return <LoginPage />;
|
||||
|
||||
return (
|
||||
<SessionProvider>
|
||||
<AppContent />
|
||||
</SessionProvider>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.5 User Menu
|
||||
**Location:** Header component
|
||||
|
||||
**Elements:**
|
||||
- User name/email display
|
||||
- Group badges (admin/user)
|
||||
- Logout button
|
||||
- Account settings link (optional)
|
||||
|
||||
**Functionality:**
|
||||
- Dropdown menu
|
||||
- Logout calls `logout()` method
|
||||
- Shows current user info
|
||||
|
||||
#### 4.6 Session Integration
|
||||
**Update:** `frontend/src/contexts/SessionContext.jsx`
|
||||
|
||||
**Changes:**
|
||||
- Include user in WebSocket connection metadata
|
||||
- Filter sessions by current user
|
||||
- Add user info to session creation
|
||||
- Handle 401 errors by triggering AuthContext logout
|
||||
|
||||
**WebSocket Headers:**
|
||||
- Session cookie automatically included
|
||||
- Backend validates on upgrade
|
||||
|
||||
### Verification Criteria
|
||||
- [ ] Unauthenticated users see login page
|
||||
- [ ] Login redirects to Authentik
|
||||
- [ ] Successful login shows app
|
||||
- [ ] User info displayed in UI
|
||||
- [ ] Logout clears session and returns to login
|
||||
- [ ] 401 errors trigger re-authentication
|
||||
- [ ] WebSocket connects with auth
|
||||
- [ ] Sessions filtered by user
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: Production Hardening & Polish
|
||||
|
||||
### Objectives
|
||||
- Implement security best practices
|
||||
- Add monitoring and logging
|
||||
- Handle edge cases
|
||||
- Document configuration
|
||||
- Test thoroughly
|
||||
|
||||
### Tasks
|
||||
|
||||
#### 5.1 Security Enhancements
|
||||
|
||||
**CSRF Protection:**
|
||||
- Use `sameSite: 'lax'` on cookies
|
||||
- Add CSRF tokens for state-changing operations
|
||||
- Validate origin headers on WebSocket upgrade
|
||||
|
||||
**Rate Limiting:**
|
||||
- Add `express-rate-limit` to auth endpoints
|
||||
- Limit login attempts per IP
|
||||
- Limit token refresh attempts
|
||||
|
||||
**Token Security:**
|
||||
- Encrypt tokens at rest in Redis (using `crypto`)
|
||||
- Validate token expiry before use
|
||||
- Clear tokens on logout
|
||||
|
||||
**Content Security Policy:**
|
||||
- Add CSP headers
|
||||
- Allow only Authentik domain for redirects
|
||||
- Restrict inline scripts
|
||||
|
||||
#### 5.2 Logging & Monitoring
|
||||
|
||||
**Authentication Events:**
|
||||
- Log successful logins (user ID, IP, timestamp)
|
||||
- Log failed auth attempts
|
||||
- Log token refresh failures
|
||||
- Log logout events
|
||||
|
||||
**Metrics:**
|
||||
- Active sessions count
|
||||
- Authentication failures rate
|
||||
- Token refresh rate
|
||||
- WebSocket auth failures
|
||||
|
||||
**Integration:**
|
||||
- Use existing Gotify webhook for alerts
|
||||
- Log to stdout (Docker logs)
|
||||
- Consider structured logging (winston)
|
||||
|
||||
#### 5.3 Error Handling
|
||||
|
||||
**Token Expiry:**
|
||||
- Detect access token expiry
|
||||
- Auto-refresh using refresh token
|
||||
- Prompt re-login if refresh fails
|
||||
- Show clear error messages
|
||||
|
||||
**Session Expiry:**
|
||||
- Handle expired sessions gracefully
|
||||
- Show "Session expired, please login again"
|
||||
- Preserve unsaved work if possible
|
||||
|
||||
**Network Errors:**
|
||||
- Retry logic for auth endpoint calls
|
||||
- Offline detection
|
||||
- Clear error messages
|
||||
|
||||
**Authentik Downtime:**
|
||||
- Cache user info for graceful degradation
|
||||
- Allow continued use of valid sessions
|
||||
- Queue auth checks
|
||||
|
||||
#### 5.4 Environment Configuration
|
||||
|
||||
**Required Env Vars:**
|
||||
```bash
|
||||
# OIDC
|
||||
OIDC_ISSUER=https://auth.sneakercloud.de/application/o/claude-web-ui/
|
||||
OIDC_CLIENT_ID=<client_id>
|
||||
OIDC_CLIENT_SECRET=<client_secret>
|
||||
OIDC_REDIRECT_URI=https://agents.sneakercloud.de/auth/callback
|
||||
|
||||
# Session
|
||||
SESSION_SECRET=<generate_with_openssl_rand_hex_32>
|
||||
SESSION_DOMAIN=.sneakercloud.de
|
||||
SESSION_SECURE=true
|
||||
SESSION_MAX_AGE=86400000 # 24 hours
|
||||
|
||||
# Redis
|
||||
REDIS_URL=redis://localhost:6379
|
||||
REDIS_PASSWORD=<optional>
|
||||
|
||||
# App
|
||||
NODE_ENV=production
|
||||
FRONTEND_URL=https://agents.sneakercloud.de
|
||||
```
|
||||
|
||||
**docker-compose.yml Updates:**
|
||||
```yaml
|
||||
services:
|
||||
backend:
|
||||
environment:
|
||||
- OIDC_ISSUER=${OIDC_ISSUER}
|
||||
- OIDC_CLIENT_ID=${OIDC_CLIENT_ID}
|
||||
- OIDC_CLIENT_SECRET=${OIDC_CLIENT_SECRET}
|
||||
- SESSION_SECRET=${SESSION_SECRET}
|
||||
- REDIS_URL=redis://redis:6379
|
||||
depends_on:
|
||||
- redis
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
networks:
|
||||
- claude-internal
|
||||
volumes:
|
||||
- redis-data:/data
|
||||
|
||||
volumes:
|
||||
redis-data:
|
||||
```
|
||||
|
||||
#### 5.5 Documentation
|
||||
|
||||
**Create Files:**
|
||||
- `docs/AUTHENTICATION.md` - Overview of auth system
|
||||
- `docs/SETUP.md` - Step-by-step Authentik setup
|
||||
- `docs/CONFIGURATION.md` - Environment variables
|
||||
- `docs/TROUBLESHOOTING.md` - Common issues
|
||||
|
||||
**Update README.md:**
|
||||
- Add authentication section
|
||||
- Document required groups
|
||||
- Link to setup docs
|
||||
|
||||
#### 5.6 Testing
|
||||
|
||||
**Manual Tests:**
|
||||
- [ ] Fresh login flow
|
||||
- [ ] Logout and re-login
|
||||
- [ ] Session persistence across browser refresh
|
||||
- [ ] Token refresh
|
||||
- [ ] Expired session handling
|
||||
- [ ] WebSocket auth
|
||||
- [ ] Group-based access control
|
||||
- [ ] Multiple users simultaneously
|
||||
- [ ] Admin vs regular user permissions
|
||||
|
||||
**Edge Cases:**
|
||||
- [ ] Authentik downtime during login
|
||||
- [ ] Redis downtime (session loss)
|
||||
- [ ] Concurrent logins from same user
|
||||
- [ ] Token refresh during active WebSocket
|
||||
- [ ] Cookie disabled in browser
|
||||
- [ ] CORS issues
|
||||
|
||||
**Security Tests:**
|
||||
- [ ] Cannot access API without auth
|
||||
- [ ] Cannot access other users' sessions
|
||||
- [ ] XSS attacks blocked (httpOnly cookies)
|
||||
- [ ] CSRF protection works
|
||||
- [ ] Token replay attacks prevented
|
||||
|
||||
### Verification Criteria
|
||||
- [ ] All security enhancements implemented
|
||||
- [ ] Logging captures auth events
|
||||
- [ ] Error handling covers all cases
|
||||
- [ ] Documentation complete
|
||||
- [ ] All tests pass
|
||||
- [ ] Production deployment successful
|
||||
|
||||
---
|
||||
|
||||
## Implementation Timeline
|
||||
|
||||
**Phase 1:** Authentik Configuration & Backend Foundation
|
||||
**Duration:** 2-3 days
|
||||
**Blockers:** None
|
||||
|
||||
**Phase 2:** OIDC Authentication Flow
|
||||
**Duration:** 2-3 days
|
||||
**Blockers:** Phase 1 complete
|
||||
|
||||
**Phase 3:** Backend API Protection
|
||||
**Duration:** 2-3 days
|
||||
**Blockers:** Phase 2 complete
|
||||
|
||||
**Phase 4:** Frontend Authentication UI
|
||||
**Duration:** 3-4 days
|
||||
**Blockers:** Phase 3 complete
|
||||
|
||||
**Phase 5:** Production Hardening & Polish
|
||||
**Duration:** 2-3 days
|
||||
**Blockers:** Phase 4 complete
|
||||
|
||||
**Total Estimated Time:** 11-16 days
|
||||
|
||||
---
|
||||
|
||||
## Success Metrics
|
||||
|
||||
1. **Security:**
|
||||
- Zero XSS vulnerabilities (httpOnly cookies)
|
||||
- Zero unauthorized access incidents
|
||||
- All tokens encrypted at rest
|
||||
|
||||
2. **User Experience:**
|
||||
- Seamless login flow (<5 seconds)
|
||||
- Clear error messages
|
||||
- No unnecessary re-authentication
|
||||
|
||||
3. **Reliability:**
|
||||
- 99.9% authentication availability
|
||||
- Session persistence across restarts
|
||||
- Graceful degradation on errors
|
||||
|
||||
4. **Performance:**
|
||||
- <100ms auth middleware overhead
|
||||
- No impact on WebSocket latency
|
||||
- Redis session lookups <10ms
|
||||
|
||||
---
|
||||
|
||||
## Rollback Plan
|
||||
|
||||
**If Critical Issues Arise:**
|
||||
|
||||
1. **Immediate:** Disable authentication middleware
|
||||
2. **Revert:** Return to unauthenticated mode
|
||||
3. **Investigate:** Review logs and error reports
|
||||
4. **Fix:** Address issues in isolated environment
|
||||
5. **Redeploy:** With fixes applied
|
||||
|
||||
**Feature Flags:**
|
||||
- `AUTH_ENABLED=false` to disable auth
|
||||
- Keep unauthenticated code path intact during initial rollout
|
||||
|
||||
---
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
**Post-MVP:**
|
||||
- Multi-factor authentication (MFA) via Authentik
|
||||
- API keys for programmatic access
|
||||
- OAuth2 scopes for fine-grained permissions
|
||||
- Audit log for all user actions
|
||||
- Session management UI (view/revoke sessions)
|
||||
- SSO with other services via Authentik
|
||||
- User preferences storage
|
||||
- Role-based access control (RBAC) expansion
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- **Authentik Docs:** https://docs.goauthentik.io/
|
||||
- **OIDC Spec:** https://openid.net/connect/
|
||||
- **openid-client:** https://github.com/panva/node-openid-client
|
||||
- **express-session:** https://github.com/expressjs/session
|
||||
- **OWASP Auth Cheatsheet:** https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html
|
||||
Reference in New Issue
Block a user