* feat: add OIDC/SSO database schema and models (Phase 1) Add database foundation for OpenID Connect authentication: Database Migrations: - Create oidc_identities table (links users to OIDC accounts) - Create oidc_state_nonces table (OAuth state/nonce for CSRF protection) - Create auth_audit_log table (security event logging) - Make password_digest nullable in users table (allow OIDC-only users) Models: - OIDCIdentity: Links users to external OIDC providers - OIDCStateNonce: Temporary OAuth state management - AuthAuditLog: Authentication event audit trail Changes: - Updated User model to allow null password_digest - Added model associations in models/index.js - All migrations tested and verified Related to #977 * feat: add OIDC core services (Phase 2) - Install openid-client@^6.2.0 for OIDC protocol support - Implement providerConfig.js for loading providers from .env - Support single provider or numbered providers (OIDC_PROVIDER_1_*, etc.) - Auto-provision and admin email domain configuration - Provider caching for performance - Implement stateManager.js for OAuth state/nonce management - CSRF protection with 10-minute TTL - One-time use state consumption - Automatic cleanup of expired states - Implement auditService.js for authentication event logging - Track login success/failure, logout, OIDC linking/unlinking - Store IP address, user agent, and metadata - Support for event queries and retention cleanup - Add comprehensive unit tests (60 tests, all passing) - providerConfig: 36 tests for env parsing and validation - stateManager: 12 tests for state lifecycle and security - auditService: 12 tests for event logging and queries Phase 2 completes the backend core services needed for OIDC authentication. * feat: implement OIDC authentication flow (Phase 3) Core OIDC Flow (service.js): - Provider discovery with issuer caching - Authorization URL generation with state/nonce - OAuth callback handling and token exchange - ID token validation using openid-client - Token refresh functionality JIT User Provisioning (provisioningService.js): - Auto-create users from OIDC claims - Link existing email accounts to OIDC identities - Admin role assignment based on email domain rules - Automatic username generation from email - Transaction-safe identity creation Identity Management (oidcIdentityService.js): - List user's linked OIDC identities - Link additional providers to existing accounts - Unlink identities with safety checks - Prevent unlinking last auth method - Update identity claims on login HTTP Layer (controller.js + routes.js): - GET /api/oidc/providers - List configured providers - GET /api/oidc/auth/:slug - Initiate OIDC flow - GET /api/oidc/callback/:slug - Handle OAuth callback - POST /api/oidc/link/:slug - Link provider to current user - DELETE /api/oidc/unlink/:id - Unlink identity - GET /api/oidc/identities - Get user's identities Integration: - Register OIDC routes in Express app (public + authenticated) - Update auth service to reject password login for OIDC-only users - Audit logging for all OIDC operations - Session creation on successful authentication Security: - State/nonce CSRF protection - One-time use state consumption - Transaction-safe user provisioning - Foreign key constraints enforced * feat: implement OIDC frontend login flow (Phase 4) - Created OIDCProviderButtons component for SSO login options - Created OIDCCallback component for OAuth callback handling - Updated Login page to fetch and display OIDC providers - Added /auth/callback/:provider route to App.tsx - Added i18n translations for OIDC UI elements - Downgraded openid-client to v5.7.0 (CommonJS compatibility) - Fixed linting issues in backend OIDC modules Phase 4 completes the frontend login flow for OIDC/SSO authentication. Users can now see configured SSO providers on the login page. * feat: implement OIDC account linking UI (Phase 5) Add Connected Accounts section to Profile Security tab allowing users to: - View linked OIDC provider accounts - Link new SSO providers to their account - Unlink OIDC identities with validation - Prevent unlinking last authentication method Backend changes: - Add has_password virtual field to User model - Include has_password in profile API response - Track whether user has password set for validation Frontend changes: - Create oidcService for OIDC API operations - Create ConnectedAccounts component with link/unlink flows - Add confirmation dialog before unlinking accounts - Validate that users cannot unlink their last auth method - Show warning if user has no password set - Integrate Connected Accounts into SecurityTab User experience: - View all linked SSO provider accounts with email and link date - Link additional providers via "Link Provider" buttons - Unlink with two-step confirmation to prevent accidents - Clear error messages when unlinking would leave no auth method - Warning message suggesting password setup for OIDC-only users Fixes #977 * feat: complete OIDC documentation and UI improvements (Phase 6) This commit completes Phase 6 of the OIDC/SSO implementation with comprehensive documentation, bug fixes, and UI reorganization. Documentation: - Add comprehensive user guide at docs/10-oidc-sso.md with: - Setup guides for 6 major providers (Google, Okta, Keycloak, Authentik, PocketID, Azure AD) - Configuration examples for single and multiple providers - User features documentation (login, account linking, management) - Advanced topics (auto-provisioning, admin role assignment, hybrid auth) - Comprehensive troubleshooting section - Security considerations and best practices - Update README.md with OIDC/SSO section and quick setup examples Internationalization: - Add i18n support to OIDCProviderButtons component - Add translation keys for all OIDC UI text - Update English translations with "sign_in_with" key Bug Fixes: - Fix oidcService.ts to correctly unwrap API responses - Backend returns {providers: [...]} and {identities: [...]} - Frontend was expecting plain arrays, causing "map is not a function" error - Fix initiateOIDCLink to properly handle POST response UI Improvements: - Move OIDC/SSO to dedicated tab in profile settings - Create new OIDCTab component with green LinkIcon - Remove ConnectedAccounts from SecurityTab - Add OIDC tab between Security and API Keys tabs - Update ProfileSettings with new tab configuration - Security tab now focuses solely on password management Testing: - All linting passes - All tests pass (82 suites, 1223 tests) Related to #977 * feat: add OIDC/SSO translations for all 24 languages Add i18n support for OIDC/SSO features across all supported languages: - "Sign in with {{provider}}" button text - "OIDC/SSO" tab label in profile settings - OIDC authentication flow messages Translations added for: Arabic, Bulgarian, Danish, German, Greek, Spanish, Finnish, French, Indonesian, Italian, Japanese, Korean, Dutch, Norwegian, Polish, Portuguese, Romanian, Russian, Slovenian, Swedish, Turkish, Ukrainian, Vietnamese, and Chinese. * fix: resolve 13 CodeQL security alerts This commit addresses critical security vulnerabilities identified by CodeQL scanning: **Security Configuration (2 fixes)** - Fix insecure Helmet configuration - enable CSP and HSTS in production - Fix clear text cookie transmission - enable secure cookies in production **Path Injection (3 fixes)** - Add path validation in users/controller.js to prevent arbitrary file deletion - Add path validation in users/service.js for avatar operations - Add path sanitization in attachment-utils.js deleteFileFromDisk function **Cross-Site Scripting (1 fix)** - Fix XSS vulnerability in GeneralTab.tsx avatar URL handling - Add URL sanitization to prevent javascript: protocol attacks **URL Security (2 fixes)** - Fix double escaping in url/service.js HTML entity decoding - Fix incomplete URL sanitization for YouTube domain validation **Denial of Service (1 fix)** - Add loop bound protection in inboxProcessingService.js (10k char limit) **Rate Limiting (3 fixes)** - Add rate limiting to auth routes (register, verify-email) - Add rate limiting to task attachment upload/delete endpoints - Add rate limiting to user avatar upload/delete endpoints **GitHub Actions Security (1 fix)** - Add explicit read-only permissions to CI workflow Note: CSRF middleware (#10) requires frontend changes and is tracked separately. Relates to PR #1008 * fix: allow test files in path validation for tests * fix: format long condition in attachment-utils for Prettier compliance Break the path validation condition across multiple lines to meet Prettier formatting requirements and fix CI linting failure. * fix: resolve CodeQL security alerts - Add rate limiting to OIDC authentication routes using authLimiter and authenticatedApiLimiter - Implement CSRF protection middleware using csrf-sync (skips for API tokens and test environment) - Add CSRF token endpoint at /api/csrf-token - Fix incomplete URL scheme validation in GeneralTab to block all dangerous schemes (javascript:, data:, vbscript:, file:) This addresses 5 high-severity CodeQL security vulnerabilities: - Missing rate limiting on OIDC auth routes - Missing CSRF middleware protection - Incomplete URL sanitization in avatar handling All 1223 tests passing. * fix: implement CSRF protection with lusca for CodeQL compliance Add CSRF protection using lusca.csrf (CodeQL's recommended library) to protect session-based authentication while supporting hybrid auth patterns. Implementation: - Pre-check middleware marks exempt requests (test env, Bearer tokens) - Lusca CSRF middleware applied with exemption flag check - Session-based requests require valid x-csrf-token header - Bearer token requests exempt (don't use cookies) - Test environment exempt for test execution This addresses CodeQL security alert js/missing-token-validation while maintaining support for both cookie-based and token-based authentication. Related: #977 (OIDC/SSO authentication feature)
20 KiB
OIDC/SSO Authentication
This guide explains how to configure and use OpenID Connect (OIDC) Single Sign-On (SSO) authentication in Tududi.
Related: User Management, Architecture Overview
Table of Contents
- Overview
- Why Use OIDC/SSO
- Supported Providers
- Configuration
- Provider Setup Guides
- User Features
- Advanced Topics
- Troubleshooting
- Security Considerations
Overview
OIDC (OpenID Connect) is a modern authentication protocol that allows users to sign in to Tududi using external identity providers like Google, Okta, Keycloak, or any OIDC-compliant service.
Key Features:
- Single Sign-On: Use your existing corporate or personal accounts
- Just-In-Time Provisioning: New users are automatically created on first login
- Account Linking: Connect multiple authentication methods to one account
- Hybrid Authentication: Choose between email/password or SSO login
- Multiple Providers: Support for multiple OIDC providers simultaneously
Why Use OIDC/SSO
For Enterprise Users:
- Centralized identity management
- Enforce corporate security policies
- Simplified user onboarding/offboarding
- Compliance with security standards
For Self-Hosters:
- Use existing authentication infrastructure (Keycloak, Authentik)
- Reduce password fatigue
- Leverage provider security features (2FA, security keys)
- Simplify family/team access management
For Individual Users:
- One-click login with Google, Microsoft, etc.
- No need to remember another password
- Automatic profile updates from provider
Supported Providers
Tududi supports any OIDC-compliant identity provider, including:
| Provider | Type | Typical Use Case |
|---|---|---|
| Public | Personal accounts, G Suite | |
| Okta | Enterprise | Corporate SSO |
| Keycloak | Self-hosted | Open-source identity management |
| Authentik | Self-hosted | Homelab, small business |
| PocketID | Public | Decentralized identity |
| Azure AD | Enterprise | Microsoft 365 organizations |
| Generic OIDC | Any | Custom providers with .well-known/openid-configuration |
Configuration
OIDC providers are configured via environment variables in your .env file. After making changes, restart the Tududi server for them to take effect.
Single Provider Setup
For most users, a single provider is sufficient:
# Enable OIDC
OIDC_ENABLED=true
# Provider Configuration
OIDC_PROVIDER_NAME=Google
OIDC_PROVIDER_SLUG=google
OIDC_ISSUER_URL=https://accounts.google.com
OIDC_CLIENT_ID=your-client-id.apps.googleusercontent.com
OIDC_CLIENT_SECRET=your-client-secret
OIDC_SCOPE=openid profile email
# Auto-provisioning (recommended)
OIDC_AUTO_PROVISION=true
# Optional: Auto-assign admin role to specific email domains
OIDC_ADMIN_EMAIL_DOMAINS=example.com,mycompany.com
Required Variables:
OIDC_PROVIDER_NAME: Display name shown to users (e.g., "Google", "Company SSO")OIDC_PROVIDER_SLUG: URL-safe identifier (e.g., "google", "okta")OIDC_ISSUER_URL: Provider's OIDC discovery URLOIDC_CLIENT_ID: OAuth 2.0 client ID from providerOIDC_CLIENT_SECRET: OAuth 2.0 client secret from provider
Multiple Providers Setup
To support multiple providers, use numbered environment variables:
# Enable OIDC
OIDC_ENABLED=true
# Provider 1: Google
OIDC_PROVIDER_1_NAME=Google
OIDC_PROVIDER_1_SLUG=google
OIDC_PROVIDER_1_ISSUER=https://accounts.google.com
OIDC_PROVIDER_1_CLIENT_ID=xxx.apps.googleusercontent.com
OIDC_PROVIDER_1_CLIENT_SECRET=xxx
OIDC_PROVIDER_1_SCOPE=openid profile email
OIDC_PROVIDER_1_AUTO_PROVISION=true
# Provider 2: Company Okta
OIDC_PROVIDER_2_NAME=Company SSO
OIDC_PROVIDER_2_SLUG=okta
OIDC_PROVIDER_2_ISSUER=https://company.okta.com
OIDC_PROVIDER_2_CLIENT_ID=yyy
OIDC_PROVIDER_2_CLIENT_SECRET=yyy
OIDC_PROVIDER_2_AUTO_PROVISION=true
OIDC_PROVIDER_2_ADMIN_EMAIL_DOMAINS=company.com
# Provider 3: Self-hosted Authentik
OIDC_PROVIDER_3_NAME=Authentik
OIDC_PROVIDER_3_SLUG=authentik
OIDC_PROVIDER_3_ISSUER=https://auth.example.com/application/o/tududi/
OIDC_PROVIDER_3_CLIENT_ID=zzz
OIDC_PROVIDER_3_CLIENT_SECRET=zzz
OIDC_PROVIDER_3_AUTO_PROVISION=true
Numbering Rules:
- Start at
OIDC_PROVIDER_1_*, increment sequentially - No gaps allowed (1, 2, 3... not 1, 3, 5)
- Maximum: Practical limit ~5 providers (no hard limit)
Environment Variables Reference
| Variable | Required | Default | Description |
|---|---|---|---|
OIDC_ENABLED |
Yes | false |
Enable/disable OIDC feature |
OIDC_PROVIDER_NAME |
Yes | - | Provider display name |
OIDC_PROVIDER_SLUG |
Yes | - | URL-safe identifier |
OIDC_ISSUER_URL |
Yes | - | OIDC discovery endpoint |
OIDC_CLIENT_ID |
Yes | - | OAuth client ID |
OIDC_CLIENT_SECRET |
Yes | - | OAuth client secret |
OIDC_SCOPE |
No | openid profile email |
OAuth scopes |
OIDC_AUTO_PROVISION |
No | true |
Auto-create users on first login |
OIDC_ADMIN_EMAIL_DOMAINS |
No | - | Comma-separated domains for auto-admin |
BASE_URL |
Yes | - | Tududi base URL (for OAuth callbacks) |
Important: The BASE_URL variable must be set for OAuth redirects to work:
BASE_URL=http://localhost:3002 # Development
BASE_URL=https://tududi.example.com # Production
Provider Setup Guides
1. Create OAuth 2.0 Credentials
- Go to Google Cloud Console
- Create a new project or select existing
- Navigate to APIs & Services > Credentials
- Click Create Credentials > OAuth client ID
- Select Web application
- Add authorized redirect URIs:
- Development:
http://localhost:3002/api/oidc/callback/google - Production:
https://your-domain.com/api/oidc/callback/google
- Development:
- Copy Client ID and Client Secret
2. Configure Tududi
OIDC_ENABLED=true
OIDC_PROVIDER_NAME=Google
OIDC_PROVIDER_SLUG=google
OIDC_ISSUER_URL=https://accounts.google.com
OIDC_CLIENT_ID=123456789.apps.googleusercontent.com
OIDC_CLIENT_SECRET=GOCSPX-xxxxxxxxxxxxx
OIDC_SCOPE=openid profile email
OIDC_AUTO_PROVISION=true
3. Test
- Restart Tududi
- Navigate to login page
- Click "Sign in with Google"
- Approve permissions
- You should be logged in!
Okta
1. Create OIDC Application
- Log in to your Okta admin console
- Go to Applications > Applications
- Click Create App Integration
- Select OIDC - OpenID Connect
- Select Web Application
- Configure:
- Sign-in redirect URIs:
https://your-domain.com/api/oidc/callback/okta - Sign-out redirect URIs:
https://your-domain.com/login - Controlled access: Choose your access policy
- Sign-in redirect URIs:
- Save and note the Client ID and Client Secret
2. Find Your Issuer URL
Format: https://{your-domain}.okta.com
Example: https://company.okta.com
3. Configure Tududi
OIDC_ENABLED=true
OIDC_PROVIDER_NAME=Company SSO
OIDC_PROVIDER_SLUG=okta
OIDC_ISSUER_URL=https://company.okta.com
OIDC_CLIENT_ID=0oa123456789abcde
OIDC_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxx
OIDC_SCOPE=openid profile email
OIDC_AUTO_PROVISION=true
OIDC_ADMIN_EMAIL_DOMAINS=company.com
Keycloak
1. Create OIDC Client
- Log in to Keycloak admin console
- Select your realm
- Go to Clients > Create client
- Configure:
- Client type: OpenID Connect
- Client ID:
tududi - Client authentication: ON (confidential)
- Valid redirect URIs:
https://your-domain.com/api/oidc/callback/keycloak
- Go to Credentials tab and copy Client secret
2. Find Your Issuer URL
Format: https://{keycloak-domain}/realms/{realm-name}
Example: https://auth.example.com/realms/myrealm
3. Configure Tududi
OIDC_ENABLED=true
OIDC_PROVIDER_NAME=Keycloak
OIDC_PROVIDER_SLUG=keycloak
OIDC_ISSUER_URL=https://auth.example.com/realms/myrealm
OIDC_CLIENT_ID=tududi
OIDC_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxx
OIDC_SCOPE=openid profile email
OIDC_AUTO_PROVISION=true
Authentik
1. Create OAuth2/OIDC Provider
- Log in to Authentik admin interface
- Go to Applications > Providers
- Click Create and select OAuth2/OpenID Provider
- Configure:
- Name: Tududi
- Authorization flow: Choose your flow
- Redirect URIs:
https://your-domain.com/api/oidc/callback/authentik - Signing Key: Select a certificate
- Note the Client ID and Client Secret
2. Create Application
- Go to Applications > Applications
- Click Create
- Link the provider you just created
- Configure slug and other settings
3. Find Your Issuer URL
Format: https://{authentik-domain}/application/o/{application-slug}/
Example: https://auth.example.com/application/o/tududi/
4. Configure Tududi
OIDC_ENABLED=true
OIDC_PROVIDER_NAME=Authentik
OIDC_PROVIDER_SLUG=authentik
OIDC_ISSUER_URL=https://auth.example.com/application/o/tududi/
OIDC_CLIENT_ID=xxxxxxxxxxxxxxxxxxxx
OIDC_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxx
OIDC_SCOPE=openid profile email
OIDC_AUTO_PROVISION=true
PocketID
1. Register Application
- Go to PocketID Developer Console
- Create a new application
- Configure:
- Name: Tududi
- Redirect URI:
https://your-domain.com/api/oidc/callback/pocketid
- Note the Client ID and Client Secret
2. Configure Tududi
OIDC_ENABLED=true
OIDC_PROVIDER_NAME=PocketID
OIDC_PROVIDER_SLUG=pocketid
OIDC_ISSUER_URL=https://pocketid.app
OIDC_CLIENT_ID=xxxxxxxxxxxxxxxxxxxx
OIDC_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxx
OIDC_SCOPE=openid profile email
OIDC_AUTO_PROVISION=true
Azure AD
1. Register Application
- Go to Azure Portal
- Navigate to Azure Active Directory > App registrations
- Click New registration
- Configure:
- Name: Tududi
- Supported account types: Choose your option
- Redirect URI: Web -
https://your-domain.com/api/oidc/callback/azure
- After creation, go to Certificates & secrets
- Create a new Client secret and copy it
- Note the Application (client) ID
2. Find Your Tenant ID
Go to Azure Active Directory > Overview and copy the Tenant ID
3. Configure Tududi
OIDC_ENABLED=true
OIDC_PROVIDER_NAME=Microsoft
OIDC_PROVIDER_SLUG=azure
OIDC_ISSUER_URL=https://login.microsoftonline.com/{tenant-id}/v2.0
OIDC_CLIENT_ID=12345678-1234-1234-1234-123456789012
OIDC_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxx
OIDC_SCOPE=openid profile email
OIDC_AUTO_PROVISION=true
Replace {tenant-id} with your actual tenant ID.
User Features
Logging In with SSO
First-Time Users:
- Navigate to Tududi login page
- Click the provider button (e.g., "Sign in with Google")
- You'll be redirected to the provider's login page
- Approve the requested permissions
- You'll be redirected back to Tududi and logged in
- A new account is automatically created (if auto-provisioning is enabled)
Returning Users:
- Click your provider button on the login page
- If already logged in to provider, you'll be immediately authenticated
- Redirected to the Today page
Account Linking
Users with existing email/password accounts can link SSO providers:
Steps:
- Log in with email/password
- Go to Profile > Security tab
- Scroll to Connected Accounts section
- Click Link [Provider Name]
- Approve permissions at provider
- Provider is now linked to your account
Benefits:
- Log in with either email/password OR SSO
- Switch between auth methods freely
- Maintain single account with multiple login options
Managing Connected Accounts
View Connected Accounts:
Go to Profile > Security > Connected Accounts to see:
- Linked providers
- Email addresses from each provider
- Date first linked
- Last login date
Unlink Account:
- Click Unlink next to the provider
- Confirm the action
Important: You cannot unlink your last authentication method. You must have either:
- A password set, OR
- At least one OIDC identity linked
Advanced Topics
Auto-Provisioning
When OIDC_AUTO_PROVISION=true (default), new users are automatically created on first login.
How It Works:
- User completes SSO login
- Tududi checks if an OIDC identity exists for this provider + user ID
- If not, checks if a user with the email exists:
- User exists: Links OIDC identity to existing user
- User doesn't exist: Creates new user with:
- Email from OIDC claims (verified)
- Username from email prefix
- No password (OIDC-only account)
- Optional admin role (if domain matches)
- User is logged in
Disable Auto-Provisioning:
OIDC_AUTO_PROVISION=false
When disabled:
- Only users with pre-linked OIDC identities can log in
- New SSO users are rejected with an error
- Useful for invite-only deployments
Admin Role Assignment
Automatically grant admin privileges based on email domain:
OIDC_ADMIN_EMAIL_DOMAINS=company.com,example.org
Rules:
- New users with emails from these domains become admins
- Applies only on first provisioning (not on subsequent logins)
- Existing non-admin users are not promoted
- Case-insensitive domain matching
Use Cases:
- Corporate deployments: Trust internal email domains
- Family instances: Trust your domain
- Multi-tenant: Different providers for different admin groups
Hybrid Authentication
Tududi supports hybrid authentication where users choose their preferred method:
Scenarios:
- Email/Password Only: Traditional authentication
- SSO Only: OIDC-only users (no password set)
- Both: Users can use either method
For OIDC-Only Users:
If a user was created via SSO and has no password:
- Attempting email/password login shows: "This account uses SSO. Please sign in with your SSO provider."
- User must log in via SSO or set a password via password reset
For Email/Password Users:
- Can link SSO providers at any time
- Both auth methods work independently
- Unlinking SSO doesn't affect password login
Troubleshooting
"Provider not found" Error
Cause: The provider slug in the URL doesn't match any configured provider.
Solution:
- Check
.envfile for correctOIDC_PROVIDER_SLUGvalue - Ensure slug is URL-safe (lowercase, no spaces)
- Restart server after
.envchanges
"Invalid state parameter" Error
Cause: OAuth state validation failed (security check).
Possible Reasons:
- State expired (>10 minutes old)
- Callback URL mismatch
- State already consumed
Solution:
- Start the login flow again (don't reuse old URLs)
- Check
BASE_URLmatches your actual domain - Verify callback URL in provider settings
"Auto-provisioning disabled" Error
Cause: User doesn't exist and OIDC_AUTO_PROVISION=false.
Solution:
- Enable auto-provisioning:
OIDC_AUTO_PROVISION=true, OR - Create user account manually first, then link SSO
Provider Button Not Showing
Cause: Provider not loaded from .env.
Solution:
- Check
OIDC_ENABLED=trueis set - Verify all required variables are present
- Check for typos in variable names
- Restart server
- Check browser console for API errors
"Invalid grant" or Token Errors
Cause: JWT validation failed.
Possible Reasons:
- Wrong client secret
- Clock skew between servers
- Issuer URL mismatch
Solution:
- Verify
OIDC_CLIENT_SECRETmatches provider - Ensure server time is accurate (NTP sync)
- Check
OIDC_ISSUER_URLexactly matches provider's issuer claim
Callback URL Mismatch
Cause: Redirect URI configured in provider doesn't match Tududi's callback.
Solution:
- Callback URL format:
{BASE_URL}/api/oidc/callback/{slug} - Example:
https://tududi.example.com/api/oidc/callback/google - Must match exactly in provider settings (including http/https)
- Update provider settings and restart Tududi
Can't Unlink Last Auth Method
Cause: Safety check prevents losing all access.
Solution:
- Set a password first (Profile > Security)
- Then unlink OIDC identity, OR
- Link another OIDC provider first
Security Considerations
Secret Storage
- Client secrets are stored in
.envfile (plaintext) - Ensure
.envis never committed to version control (already in.gitignore) - Use proper file permissions:
chmod 600 .envon Linux/macOS - For production, consider Docker secrets or Kubernetes secrets
OAuth Flow Security
Tududi implements standard OAuth 2.0 security measures:
- CSRF Protection: Cryptographically random state parameter (32 bytes)
- Replay Protection: State is one-time use, 10-minute TTL
- JWT Validation: ID tokens verified against provider's JWKS
- Nonce Validation: Prevents token reuse attacks
- TLS Enforcement: Always use HTTPS in production
Data Privacy
What's Stored:
- OIDC subject (provider's user ID)
- Email, name, profile picture from claims
- Full raw claims (JSON) for debugging
- First/last login timestamps
What's Not Stored:
- Provider passwords
- OAuth access tokens (discarded after login)
- Refresh tokens
Audit Trail
All authentication events are logged (if audit logging is enabled):
- Login success/failure
- OIDC linking/unlinking
- Provider information
- IP address and user agent
Check logs at: /backend/logs/ (if enabled)
Rate Limiting
OIDC endpoints are protected by rate limiting:
/api/oidc/auth/*: 5 requests per 15 minutes per IP/api/oidc/callback/*: 5 requests per 15 minutes per IP- Linking/unlinking: Standard authenticated API limits
Best Practices
- Use HTTPS: Always use HTTPS in production
- Restrict Callback URLs: Only whitelist exact callback URLs needed
- Rotate Secrets: Periodically rotate client secrets
- Monitor Logs: Watch for suspicious authentication attempts
- Limit Providers: Only enable providers you trust
- Email Verification: Trust provider's email verification
- Review Permissions: Only request necessary OAuth scopes
Migration from Email/Password
Existing deployments can gradually adopt OIDC:
Step 1: Configure Providers
Add OIDC configuration to .env without removing email/password support.
Step 2: Notify Users
Announce new SSO option to users.
Step 3: Users Link Accounts
Existing users can link SSO providers to their accounts via Profile > Security.
Step 4: Optional - Disable Email/Password
Not recommended, but possible by customizing the frontend Login component.
Rollback:
Simply set OIDC_ENABLED=false and restart. Email/password authentication continues to work.
API Integration
Fetch Available Providers:
GET /api/oidc/providers
Response:
[
{
"slug": "google",
"name": "Google",
"button_text": "Sign in with {name}",
"type": "oidc"
}
]
Initiate Login Flow:
Redirect user to:
GET /api/oidc/auth/{slug}
User's Connected Identities:
GET /api/oidc/identities
Authorization: Bearer <token>
See Swagger API docs for full API reference.
Support
Issues: GitHub Issues Discussions: GitHub Discussions Discord: Join our community
Related Documentation:
Document Version: 1.0.0 Last Updated: 2026-04-20 Maintainer: Update when OIDC features change