2025-11-23 20:12:09 -03:00
# User Authentication
2025-11-24 13:02:30 -03:00
General Bots uses a directory service component for user authentication and authorization. No passwords are stored internally in General Bots.
2025-11-23 20:12:09 -03:00
## Overview
2025-11-24 13:02:30 -03:00
Authentication in General Bots is handled entirely by the directory service, which provides:
2025-11-23 20:12:09 -03:00
- User identity management
- OAuth 2.0 / OpenID Connect (OIDC) authentication
- Single Sign-On (SSO) capabilities
- Multi-factor authentication (MFA)
- User and organization management
- Role-based access control (RBAC)
## Architecture
### Directory Service Integration
2025-11-24 13:02:30 -03:00
General Bots integrates with the directory service through:
2025-11-23 20:12:09 -03:00
- **DirectoryClient**: Client for API communication
- **AuthService**: Service layer for authentication operations
- **OIDC Flow**: Standard OAuth2/OIDC authentication flow
- **Service Account**: For administrative operations
### No Internal Password Storage
- **No password_hash columns**: Users table only stores directory user IDs
- **No Argon2 hashing**: All password operations handled by directory service
- **No password reset logic**: Managed through directory service's built-in flows
2025-11-24 13:02:30 -03:00
- **Session tokens only**: General Bots only manages session state
2025-11-23 20:12:09 -03:00
## Authentication Flow
### Authentication Architecture
2025-11-24 13:02:30 -03:00
< svg viewBox = "0 0 800 600" xmlns = "http://www.w3.org/2000/svg" >
< defs >
< marker id = "arrowauth1" markerWidth = "10" markerHeight = "10" refX = "9" refY = "3" orient = "auto" >
< polygon points = "0 0, 10 3, 0 6" fill = " #666 " />
< / marker >
< marker id = "arrowauth1b" markerWidth = "10" markerHeight = "10" refX = "0" refY = "3" orient = "auto" >
< polygon points = "10 0, 0 3, 10 6" fill = " #666 " />
< / marker >
< / defs >
<!-- Browser Box -->
< rect x = "50" y = "50" width = "150" height = "80" rx = "5" fill = "none" stroke = " #666 " stroke-width = "2" />
< text x = "125" y = "85" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "14" font-weight = "bold" > Browser</ text >
<!-- General Bots Box -->
< rect x = "325" y = "50" width = "150" height = "80" rx = "5" fill = "none" stroke = " #666 " stroke-width = "2" />
< text x = "400" y = "85" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "14" font-weight = "bold" > General Bots</ text >
<!-- Directory Service Box -->
< rect x = "600" y = "50" width = "150" height = "80" rx = "5" fill = "none" stroke = " #666 " stroke-width = "2" />
< text x = "675" y = "85" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "14" font-weight = "bold" > Directory</ text >
< text x = "675" y = "105" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "14" > Service</ text >
<!-- Database Box -->
< rect x = "325" y = "480" width = "150" height = "80" rx = "5" fill = "none" stroke = " #666 " stroke-width = "2" />
< text x = "400" y = "505" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "14" font-weight = "bold" > PostgreSQL</ text >
< text x = "400" y = "525" text-anchor = "middle" fill = " #666 " font-family = "monospace" font-size = "12" > • Sessions</ text >
< text x = "400" y = "545" text-anchor = "middle" fill = " #666 " font-family = "monospace" font-size = "12" > • User Refs</ text >
<!-- Browser - General Bots bidirectional arrow -->
< path d = "M 200 90 L 325 90" stroke = " #666 " stroke-width = "2" fill = "none" marker-end = "url( #arrowauth1 )" />
< path d = "M 325 90 L 200 90" stroke = " #666 " stroke-width = "2" fill = "none" marker-end = "url( #arrowauth1b )" />
<!-- General Bots - Directory bidirectional arrow -->
< path d = "M 475 90 L 600 90" stroke = " #666 " stroke-width = "2" fill = "none" marker-end = "url( #arrowauth1 )" />
< path d = "M 600 90 L 475 90" stroke = " #666 " stroke-width = "2" fill = "none" marker-end = "url( #arrowauth1b )" />
<!-- Vertical flow lines -->
< line x1 = "125" y1 = "130" x2 = "125" y2 = "450" stroke = " #666 " stroke-width = "1" stroke-dasharray = "2,2" />
< line x1 = "400" y1 = "130" x2 = "400" y2 = "450" stroke = " #666 " stroke-width = "1" stroke-dasharray = "2,2" />
< line x1 = "675" y1 = "130" x2 = "675" y2 = "450" stroke = " #666 " stroke-width = "1" stroke-dasharray = "2,2" />
<!-- Flow steps -->
<!-- 1. Login Request -->
< path d = "M 125 170 L 395 170" stroke = " #4CAF50 " stroke-width = "2" fill = "none" marker-end = "url( #arrowauth1 )" />
< text x = "260" y = "160" text-anchor = "middle" fill = " #4CAF50 " font-family = "monospace" font-size = "11" > 1. Login Request</ text >
<!-- 2. Redirect to OIDC -->
< path d = "M 405 200 L 670 200" stroke = " #2196F3 " stroke-width = "2" fill = "none" marker-end = "url( #arrowauth1 )" />
< text x = "537" y = "190" text-anchor = "middle" fill = " #2196F3 " font-family = "monospace" font-size = "11" > 2. Redirect to OIDC</ text >
<!-- 3. Show Login Page -->
< path d = "M 670 230 L 130 230" stroke = " #FF9800 " stroke-width = "2" fill = "none" marker-end = "url( #arrowauth1b )" />
< text x = "400" y = "220" text-anchor = "middle" fill = " #FF9800 " font-family = "monospace" font-size = "11" > 3. Show Login Page</ text >
<!-- 4. Enter Credentials -->
< path d = "M 130 260 L 670 260" stroke = " #9C27B0 " stroke-width = "2" fill = "none" marker-end = "url( #arrowauth1 )" />
< text x = "400" y = "250" text-anchor = "middle" fill = " #9C27B0 " font-family = "monospace" font-size = "11" > 4. Enter Credentials</ text >
<!-- 5. Return Tokens -->
< path d = "M 670 290 L 405 290" stroke = " #E91E63 " stroke-width = "2" fill = "none" marker-end = "url( #arrowauth1b )" />
< text x = "537" y = "280" text-anchor = "middle" fill = " #E91E63 " font-family = "monospace" font-size = "11" > 5. Return Tokens</ text >
<!-- 6. Set Session Cookie -->
< path d = "M 395 320 L 130 320" stroke = " #795548 " stroke-width = "2" fill = "none" marker-end = "url( #arrowauth1b )" />
< text x = "262" y = "310" text-anchor = "middle" fill = " #795548 " font-family = "monospace" font-size = "11" > 6. Set Session Cookie</ text >
<!-- 7. Authenticated! -->
< text x = "125" y = "360" text-anchor = "middle" fill = " #4CAF50 " font-family = "monospace" font-size = "12" font-weight = "bold" > 7. Authenticated!</ text >
<!-- Database sync -->
< path d = "M 675 450 L 475 520" stroke = " #666 " stroke-width = "2" fill = "none" marker-end = "url( #arrowauth1 )" stroke-dasharray = "5,5" />
< text x = "575" y = "480" text-anchor = "middle" fill = " #666 " font-family = "monospace" font-size = "11" > User Sync</ text >
< / svg >
2025-11-23 20:12:09 -03:00
### User Registration
2025-11-24 13:02:30 -03:00
< svg viewBox = "0 0 700 500" xmlns = "http://www.w3.org/2000/svg" >
< defs >
< marker id = "arrowreg" markerWidth = "10" markerHeight = "10" refX = "9" refY = "3" orient = "auto" >
< polygon points = "0 0, 10 3, 0 6" fill = " #666 " />
< / marker >
< / defs >
<!-- Title -->
< text x = "350" y = "30" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "16" font-weight = "bold" > User Registration Flow</ text >
<!-- Entity headers -->
< text x = "100" y = "70" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "14" font-weight = "bold" > User</ text >
< text x = "350" y = "70" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "14" font-weight = "bold" > General Bots</ text >
< text x = "600" y = "70" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "14" font-weight = "bold" > Directory</ text >
<!-- Vertical lifelines -->
< line x1 = "100" y1 = "80" x2 = "100" y2 = "450" stroke = " #666 " stroke-width = "1" stroke-dasharray = "2,2" />
< line x1 = "350" y1 = "80" x2 = "350" y2 = "450" stroke = " #666 " stroke-width = "1" stroke-dasharray = "2,2" />
< line x1 = "600" y1 = "80" x2 = "600" y2 = "450" stroke = " #666 " stroke-width = "1" stroke-dasharray = "2,2" />
<!-- Register -->
< path d = "M 100 120 L 345 120" stroke = " #4CAF50 " stroke-width = "2" fill = "none" marker-end = "url( #arrowreg )" />
< text x = "225" y = "110" text-anchor = "middle" fill = " #4CAF50 " font-family = "monospace" font-size = "12" > Register</ text >
<!-- Create -->
< path d = "M 355 150 L 595 150" stroke = " #2196F3 " stroke-width = "2" fill = "none" marker-end = "url( #arrowreg )" />
< text x = "475" y = "140" text-anchor = "middle" fill = " #2196F3 " font-family = "monospace" font-size = "12" > Create</ text >
<!-- Zitadel operations -->
< rect x = "605" y = "170" width = "180" height = "100" rx = "3" fill = " #f0f4f8 " stroke = " #666 " stroke-width = "1" />
< text x = "615" y = "190" fill = " #666 " font-family = "monospace" font-size = "11" > ► Generate ID</ text >
< text x = "615" y = "215" fill = " #666 " font-family = "monospace" font-size = "11" > ► Hash Password</ text >
< text x = "615" y = "240" fill = " #666 " font-family = "monospace" font-size = "11" > ► Store User</ text >
<!-- User ID returned -->
< path d = "M 595 290 L 355 290" stroke = " #FF9800 " stroke-width = "2" fill = "none" marker-end = "url( #arrowreg )" />
< text x = "475" y = "280" text-anchor = "middle" fill = " #FF9800 " font-family = "monospace" font-size = "12" > User ID</ text >
<!-- General Bots operations -->
< rect x = "355" y = "310" width = "180" height = "75" rx = "3" fill = " #f0f4f8 " stroke = " #666 " stroke-width = "1" />
< text x = "365" y = "330" fill = " #666 " font-family = "monospace" font-size = "11" > ► Create Local Ref</ text >
< text x = "365" y = "355" fill = " #666 " font-family = "monospace" font-size = "11" > ► Start Session</ text >
<!-- Token returned -->
< path d = "M 345 405 L 105 405" stroke = " #9C27B0 " stroke-width = "2" fill = "none" marker-end = "url( #arrowreg )" />
< text x = "225" y = "395" text-anchor = "middle" fill = " #9C27B0 " font-family = "monospace" font-size = "12" > Token</ text >
< / svg >
2025-11-23 20:12:09 -03:00
1. User registration request sent to directory service
2. Directory service creates user account
3. User ID returned to BotServer
2025-11-24 13:02:30 -03:00
4. General Bots creates local user reference
5. Session established with General Bots
2025-11-23 20:12:09 -03:00
### User Login
2025-11-24 13:02:30 -03:00
< svg viewBox = "0 0 800 700" xmlns = "http://www.w3.org/2000/svg" >
< defs >
< marker id = "arrowlogin" markerWidth = "10" markerHeight = "10" refX = "9" refY = "3" orient = "auto" >
< polygon points = "0 0, 10 3, 0 6" fill = " #666 " />
< / marker >
< / defs >
<!-- Title -->
< text x = "400" y = "30" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "16" font-weight = "bold" > User Login Flow</ text >
<!-- Entity headers -->
< text x = "100" y = "70" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "14" font-weight = "bold" > Browser</ text >
< text x = "400" y = "70" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "14" font-weight = "bold" > General Bots</ text >
< text x = "700" y = "70" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "14" font-weight = "bold" > Directory</ text >
<!-- Vertical lifelines -->
< line x1 = "100" y1 = "80" x2 = "100" y2 = "650" stroke = " #666 " stroke-width = "1" stroke-dasharray = "2,2" />
< line x1 = "400" y1 = "80" x2 = "400" y2 = "650" stroke = " #666 " stroke-width = "1" stroke-dasharray = "2,2" />
< line x1 = "700" y1 = "80" x2 = "700" y2 = "650" stroke = " #666 " stroke-width = "1" stroke-dasharray = "2,2" />
<!-- 1. GET /login -->
< path d = "M 100 120 L 395 120" stroke = " #4CAF50 " stroke-width = "2" fill = "none" marker-end = "url( #arrowlogin )" />
< text x = "250" y = "110" text-anchor = "middle" fill = " #4CAF50 " font-family = "monospace" font-size = "11" > GET /login</ text >
<!-- 2. 302 Redirect -->
< path d = "M 395 160 L 105 160" stroke = " #2196F3 " stroke-width = "2" fill = "none" marker-end = "url( #arrowlogin )" />
< text x = "250" y = "150" text-anchor = "middle" fill = " #2196F3 " font-family = "monospace" font-size = "11" > 302 Redirect</ text >
< text x = "250" y = "175" text-anchor = "middle" fill = " #2196F3 " font-family = "monospace" font-size = "10" > to Directory</ text >
<!-- 3. Show Login Form -->
< path d = "M 105 220 L 695 220" stroke = " #FF9800 " stroke-width = "2" fill = "none" marker-end = "url( #arrowlogin )" />
< path d = "M 695 250 L 105 250" stroke = " #FF9800 " stroke-width = "2" fill = "none" marker-end = "url( #arrowlogin )" />
< text x = "400" y = "210" text-anchor = "middle" fill = " #FF9800 " font-family = "monospace" font-size = "11" > Show Login Form</ text >
<!-- 4. Submit Credentials -->
< path d = "M 105 290 L 695 290" stroke = " #9C27B0 " stroke-width = "2" fill = "none" marker-end = "url( #arrowlogin )" />
< text x = "400" y = "280" text-anchor = "middle" fill = " #9C27B0 " font-family = "monospace" font-size = "11" > Submit Credentials</ text >
<!-- Directory validation -->
< rect x = "705" y = "310" width = "150" height = "75" rx = "3" fill = " #f0f4f8 " stroke = " #666 " stroke-width = "1" />
< text x = "715" y = "330" fill = " #666 " font-family = "monospace" font-size = "11" > ► Validate</ text >
< text x = "715" y = "355" fill = " #666 " font-family = "monospace" font-size = "11" > ► Generate Tokens</ text >
<!-- 5. Redirect + Tokens -->
< path d = "M 695 405 L 105 405" stroke = " #E91E63 " stroke-width = "2" fill = "none" marker-end = "url( #arrowlogin )" />
< text x = "400" y = "395" text-anchor = "middle" fill = " #E91E63 " font-family = "monospace" font-size = "11" > Redirect + Tokens</ text >
<!-- 6. /auth/callback -->
< path d = "M 105 445 L 395 445" stroke = " #795548 " stroke-width = "2" fill = "none" marker-end = "url( #arrowlogin )" />
< text x = "250" y = "435" text-anchor = "middle" fill = " #795548 " font-family = "monospace" font-size = "11" > /auth/callback</ text >
<!-- General Bots validation -->
< rect x = "405" y = "465" width = "160" height = "100" rx = "3" fill = " #f0f4f8 " stroke = " #666 " stroke-width = "1" />
< text x = "415" y = "485" fill = " #666 " font-family = "monospace" font-size = "11" > ► Validate Tokens</ text >
< text x = "415" y = "510" fill = " #666 " font-family = "monospace" font-size = "11" > ► Create Session</ text >
< text x = "415" y = "535" fill = " #666 " font-family = "monospace" font-size = "11" > ► Store in DB</ text >
<!-- 7. Set Cookie -->
< path d = "M 395 585 L 105 585" stroke = " #607D8B " stroke-width = "2" fill = "none" marker-end = "url( #arrowlogin )" />
< text x = "250" y = "575" text-anchor = "middle" fill = " #607D8B " font-family = "monospace" font-size = "11" > Set Cookie</ text >
< text x = "250" y = "600" text-anchor = "middle" fill = " #607D8B " font-family = "monospace" font-size = "10" > Redirect to App</ text >
< / svg >
2025-11-23 20:12:09 -03:00
1. User redirected to directory service login page
2. Credentials validated by directory service
3. OIDC tokens returned via callback
2025-11-24 13:02:30 -03:00
4. General Bots validates tokens
2025-11-23 20:12:09 -03:00
5. Local session created
6. Session token issued to client
### Token Validation
2025-11-24 13:02:30 -03:00
< svg viewBox = "0 0 800 600" xmlns = "http://www.w3.org/2000/svg" >
< defs >
< marker id = "arrowval" markerWidth = "10" markerHeight = "10" refX = "9" refY = "3" orient = "auto" >
< polygon points = "0 0, 10 3, 0 6" fill = " #666 " />
< / marker >
< / defs >
<!-- Title -->
< text x = "400" y = "30" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "16" font-weight = "bold" > Token Validation Flow</ text >
<!-- Request Flow Column -->
< text x = "200" y = "70" text-anchor = "middle" fill = " #666 " font-family = "monospace" font-size = "13" > Request Flow</ text >
<!-- Validation Pipeline Column -->
< text x = "600" y = "70" text-anchor = "middle" fill = " #666 " font-family = "monospace" font-size = "13" > Validation Pipeline</ text >
<!-- Flow arrows -->
< path d = "M 200 85 L 200 110" stroke = " #666 " stroke-width = "2" fill = "none" marker-end = "url( #arrowval )" />
< path d = "M 600 85 L 600 110" stroke = " #666 " stroke-width = "2" fill = "none" marker-end = "url( #arrowval )" />
<!-- Request + Cookie -->
< rect x = "125" y = "120" width = "150" height = "60" rx = "5" fill = " #f0f4f8 " stroke = " #666 " stroke-width = "2" />
< text x = "200" y = "145" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "12" > Request</ text >
< text x = "200" y = "165" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "12" > + Cookie</ text >
<!-- Extract Token -->
< rect x = "450" y = "120" width = "300" height = "60" rx = "5" fill = " #e3f2fd " stroke = " #2196F3 " stroke-width = "2" />
< text x = "600" y = "145" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "12" > Extract Token</ text >
< text x = "600" y = "165" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "12" > from Cookie/Header</ text >
<!-- General Bots Validates -->
< rect x = "125" y = "220" width = "150" height = "60" rx = "5" fill = " #f0f4f8 " stroke = " #666 " stroke-width = "2" />
< text x = "200" y = "245" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "12" > General Bots</ text >
< text x = "200" y = "265" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "12" > Validates</ text >
<!-- Check Session -->
< rect x = "450" y = "220" width = "300" height = "60" rx = "5" fill = " #e8f5e9 " stroke = " #4CAF50 " stroke-width = "2" />
< text x = "600" y = "245" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "12" > Check Session</ text >
< text x = "600" y = "265" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "12" > in Local Cache</ text >
<!-- Connection between boxes -->
< path d = "M 450 250 L 275 250" stroke = " #666 " stroke-width = "2" fill = "none" marker-end = "url( #arrowval )" />
<!-- Decision branches -->
< text x = "760" y = "255" fill = " #4CAF50 " font-family = "monospace" font-size = "11" > ► Valid? Continue</ text >
< text x = "760" y = "275" fill = " #FF9800 " font-family = "monospace" font-size = "11" > ► Expired?</ text >
<!-- Directory Refresh -->
< rect x = "125" y = "320" width = "150" height = "60" rx = "5" fill = " #f0f4f8 " stroke = " #666 " stroke-width = "2" />
< text x = "200" y = "345" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "12" > Directory</ text >
< text x = "200" y = "365" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "12" > Refresh</ text >
<!-- Refresh with Directory API -->
< rect x = "450" y = "320" width = "300" height = "60" rx = "5" fill = " #fff3e0 " stroke = " #FF9800 " stroke-width = "2" />
< text x = "600" y = "345" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "12" > Refresh with</ text >
< text x = "600" y = "365" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "12" > Directory API</ text >
<!-- Connection for refresh -->
< path d = "M 450 350 L 275 350" stroke = " #666 " stroke-width = "2" fill = "none" marker-end = "url( #arrowval )" />
<!-- Process Request -->
< rect x = "125" y = "420" width = "150" height = "60" rx = "5" fill = " #f0f4f8 " stroke = " #666 " stroke-width = "2" />
< text x = "200" y = "445" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "12" > Process</ text >
< text x = "200" y = "465" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "12" > Request</ text >
<!-- Load User Context -->
< rect x = "450" y = "420" width = "300" height = "60" rx = "5" fill = " #f3e5f5 " stroke = " #9C27B0 " stroke-width = "2" />
< text x = "600" y = "445" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "12" > Load User Context</ text >
< text x = "600" y = "465" text-anchor = "middle" fill = " #333 " font-family = "monospace" font-size = "12" > Apply Permissions</ text >
<!-- Flow arrows between stages -->
< path d = "M 200 180 L 200 220" stroke = " #666 " stroke-width = "2" fill = "none" marker-end = "url( #arrowval )" />
< path d = "M 200 280 L 200 320" stroke = " #666 " stroke-width = "2" fill = "none" marker-end = "url( #arrowval )" />
< path d = "M 200 380 L 200 420" stroke = " #666 " stroke-width = "2" fill = "none" marker-end = "url( #arrowval )" />
< path d = "M 600 180 L 600 220" stroke = " #666 " stroke-width = "2" fill = "none" marker-end = "url( #arrowval )" />
< path d = "M 600 280 L 600 320" stroke = " #666 " stroke-width = "2" fill = "none" marker-end = "url( #arrowval )" />
< path d = "M 600 380 L 600 420" stroke = " #666 " stroke-width = "2" fill = "none" marker-end = "url( #arrowval )" />
< / svg >
2025-11-23 20:12:09 -03:00
1. Client includes session token
2025-11-24 13:02:30 -03:00
2. General Bots validates local session
2025-11-23 20:12:09 -03:00
3. Optional: Refresh with directory service if expired
4. User context loaded from directory service
5. Request processed with user identity
## Directory Service Configuration
### Auto-Configuration
2025-11-24 13:02:30 -03:00
During bootstrap, General Bots automatically:
1. Installs directory service via installer.rs
2025-11-23 20:12:09 -03:00
2. Configures directory service with PostgreSQL
3. Creates default organization
4. Sets up service account
5. Creates initial admin user
6. Configures OIDC application
## Database Schema
### Users Table (Simplified)
| Column | Type | Description |
|--------|------|-------------|
2025-11-24 13:02:30 -03:00
| id | UUID | Internal General Bots ID |
2025-11-23 20:12:09 -03:00
| directory_id | TEXT | User ID in directory service |
| username | TEXT | Cached username |
| email | TEXT | Cached email |
| created_at | TIMESTAMPTZ | First login time |
| updated_at | TIMESTAMPTZ | Last sync with directory |
Note: No password_hash or any password-related fields exist.
### User Sessions Table
| Column | Type | Description |
|--------|------|-------------|
| id | UUID | Session ID |
| user_id | UUID | Reference to users table |
2025-11-24 13:02:30 -03:00
| session_token | TEXT | General Bots session token |
| directory_token | TEXT | Cached OIDC token |
2025-11-23 20:12:09 -03:00
| expires_at | TIMESTAMPTZ | Session expiration |
| created_at | TIMESTAMPTZ | Session start |
## Authentication Endpoints
### Login Initiation
```
GET /auth/login
```
Redirects to Zitadel login page with OIDC parameters.
### OAuth Callback
```
GET /auth/callback?code=...& state=...
```
Handles return from Zitadel after successful authentication.
### Logout
```
POST /auth/logout
```
Terminates local session and optionally triggers Zitadel logout.
### Session Validation
```
GET /auth/validate
Headers: Authorization: Bearer {session_token}
```
2025-11-24 13:02:30 -03:00
## Directory Service Features
2025-11-23 20:12:09 -03:00
### User Management
2025-11-24 13:02:30 -03:00
- Create, update, delete users
- Password reset flows
2025-11-23 20:12:09 -03:00
- Email verification
2025-11-24 13:02:30 -03:00
- Profile management
2025-11-23 20:12:09 -03:00
- Password policies (managed in Zitadel)
- Account locking
- Password recovery
### Multi-Factor Authentication
Configured in Zitadel:
- TOTP (Time-based One-Time Passwords)
- WebAuthn/FIDO2
- SMS OTP (if configured)
- Email OTP
### Single Sign-On
- One login for all applications
- Session management across services
- Centralized user directory
- External IdP integration
### Organizations
- Multi-tenant support
- Organization-specific policies
- Delegated administration
- User isolation
## Directory Service Integration
2025-11-24 13:02:30 -03:00
### Directory Client Implementation
2025-11-23 20:12:09 -03:00
Located in `src/directory/client.rs` :
- Manages API communication
- Handles token refresh
- Caches access tokens
- Provides user operations
### AuthService
Located in `src/directory/mod.rs` :
- High-level authentication operations
- Session management
- User profile caching
- Group/role management
## Security Benefits
### Centralized Security
- Professional identity platform
- Regular security updates
- Compliance certifications
- Audit logging
### No Password Liability
- No password storage risks
- No hashing implementation errors
- No password database leaks
- Reduced compliance burden
### Advanced Features
- Passwordless authentication
- Adaptive authentication
- Risk-based access control
- Session security policies
## User Operations
### Creating Users
2025-11-24 13:36:09 -03:00
Creating users via Directory Client:
- Username: john_doe
- Email: john@example .com
- First name: John
- Last name: Doe
- Password: Set through Directory UI or email flow
2025-11-23 20:12:09 -03:00
### Getting User Info
2025-11-24 13:36:09 -03:00
User information is fetched from the Directory service using the directory ID.
2025-11-23 20:12:09 -03:00
### Managing Sessions
2025-11-24 13:02:30 -03:00
Sessions are managed locally by General Bots but authenticated through Directory Service:
- Session creation after Directory auth
2025-11-23 20:12:09 -03:00
- Local session tokens for performance
- Periodic validation with Zitadel
- Session termination on logout
## Default Users
During bootstrap, the system creates:
1. **Admin User**
- Username: admin (configurable)
- Email: admin@localhost
2025-11-24 13:02:30 -03:00
- Password: **Randomly generated** (displayed once during setup)
2025-11-23 20:12:09 -03:00
- Role: Administrator
2. **Regular User**
- Username: user
- Email: user@default
2025-11-24 13:02:30 -03:00
- Password: **Randomly generated** (displayed once during setup)
2025-11-23 20:12:09 -03:00
- Role: Standard user
## Groups and Roles
### Organization Management
- Organizations created in Zitadel
- Users assigned to organizations
- Roles defined per organization
- Permissions inherited from roles
### Role-Based Access
- Admin: Full system access
- User: Standard bot interaction
- Custom roles: Defined in Zitadel
## Monitoring and Audit
2025-11-24 13:02:30 -03:00
### Directory Service Audit Logs
2025-11-23 20:12:09 -03:00
- All authentication events logged
- User actions tracked
- Administrative changes recorded
- Security events monitored
### Session Metrics
2025-11-24 13:02:30 -03:00
General Bots tracks:
2025-11-23 20:12:09 -03:00
- Active sessions count
- Session creation rate
- Failed authentication attempts
- Token refresh frequency
## Troubleshooting
### Common Issues
1. **Zitadel Connection Failed**
- Check Zitadel is running on port 8080
- Verify ZITADEL_ISSUER_URL
- Check network connectivity
2. **Authentication Fails**
- Verify client credentials
- Check redirect URI configuration
- Review Zitadel logs
3. **Session Issues**
- Clear browser cookies
- Check session expiry settings
- Verify token refresh logic
## Best Practices
1. **Use Zitadel UI** : Manage users through Zitadel interface
2. **Configure MFA** : Enable multi-factor for admin accounts
3. **Regular Updates** : Keep Zitadel updated
4. **Monitor Logs** : Review authentication logs regularly
5. **Session Timeout** : Configure appropriate session duration
6. **Secure Communication** : Use HTTPS in production
## Migration from Other Systems
When migrating from password-based systems:
1. Export user data (without passwords)
2. Import users into Zitadel
3. Force password reset for all users
4. Update application to use OIDC flow
5. Remove password-related code
## Summary
2025-11-24 13:02:30 -03:00
General Bots' integration with the Directory Service provides enterprise-grade authentication without the complexity and risk of managing passwords internally. All authentication operations are delegated to the Directory Service, while General Bots focuses on session management and bot interactions.