FIXES: - Milestones now show correctly on encounter page (use static fallback if DB empty) - Static data preserved as MILESTONES_DATA_STATIC for compatibility - Database-driven milestones still work (admin can edit via CMS) NEW FEATURES: - OpenID Connect (OIDC) authentication support (PocketID, Keycloak, Azure AD, etc.) - Comprehensive setup guide: OPENID_SETUP.md - Auto-linking existing users by email on SSO login - Multiple PDF upload support in Learning Hub (up to 10 files) - 100 MB per file limit (was 20 MB) - Full PDF content used for AI generation - Embeddings use first ~8K chars for semantic search IMPROVEMENTS: - Updated UI to show multiple file selection with list - Drag-and-drop supports multiple files - Better file upload validation and error handling - Added clarifying comments about embedding truncation
9.7 KiB
OpenID Connect (OIDC) / PocketID Setup Guide
This guide explains how to configure Single Sign-On (SSO) authentication using OpenID Connect providers like PocketID, Keycloak, Azure AD, Okta, or Google.
Overview
The application supports OIDC authentication alongside traditional email/password login. Once configured, users can:
- Sign in with their SSO provider (e.g., PocketID)
- Automatically link existing email accounts to their SSO identity
- Admins can optionally disable local password login entirely
Prerequisites
- An OpenID Connect provider (e.g., PocketID instance)
- Admin access to this application
- The public URL where your app is deployed (
APP_URLin.env)
Configuration Steps
1. Configure Your Identity Provider
First, register this application with your OIDC provider. You'll need:
Redirect URI / Callback URL:
https://your-domain.com/api/auth/oidc/callback
Replace your-domain.com with your actual APP_URL value.
Example: PocketID Setup
- Log into your PocketID admin panel
- Navigate to Applications → Add Application
- Set the callback URL:
https://your-domain.com/api/auth/oidc/callback - Copy the Client ID and Client Secret
Example: Keycloak Setup
- Create a new client in your Keycloak realm
- Set Access Type to
confidential - Add Valid Redirect URI:
https://your-domain.com/api/auth/oidc/callback - Save and note the Client ID and Client Secret from the Credentials tab
2. Enable OIDC in Application Settings
Log into your application as an admin user, then:
- Navigate to Admin Panel → Settings (or access
/admin-settings.html) - Look for the OpenID Connect (SSO) section
- Fill in the following fields:
| Field | Description | Example |
|---|---|---|
| Enabled | Toggle to enable OIDC | true |
| Issuer URL | Your provider's discovery endpoint | https://id.example.com or https://keycloak.example.com/realms/myrealm |
| Client ID | Application client ID from your provider | pediatric-scribe-client |
| Client Secret | Application client secret (keep confidential) | a1b2c3d4... |
| Button Label | Text shown on the SSO login button | Sign in with PocketID |
| Disable Local Auth | Hide email/password login (optional) | false (keep disabled initially) |
| Allowed IPs | Restrict SSO to specific IP ranges (optional) | Leave blank for no restriction |
- Click Save Settings
3. Test SSO Login
- Log out or open an incognito browser window
- Visit the login page
- You should see a new button: "Sign in with [Your Provider]"
- Click it and authenticate with your SSO provider
- You'll be redirected back to the application and logged in
Linking Existing Users to SSO
When a user signs in via OIDC for the first time, the system automatically links their account based on email address matching:
Scenario 1: Existing User with Matching Email
If a user already has an account with email doctor@example.com and signs in via SSO with the same email:
- The system finds the existing user by email
- Links the SSO identity (
oidc_sub) to the existing account - The user is logged in
- Future logins can use either method (email/password OR SSO)
Database update performed:
UPDATE users
SET oidc_sub = '<provider-unique-id>',
email_verified = true
WHERE email = 'doctor@example.com';
Scenario 2: New User (No Matching Email)
If the SSO email doesn't match any existing user:
- A new account is automatically created
- The user is assigned the
userrole (first user becomesadmin) - A random password is generated (not used for SSO logins)
- The user is logged in
Scenario 3: Disabled User
If an existing user is disabled (disabled = true in database):
- SSO login is blocked
- User sees an error message
- Admin must re-enable the account from the Admin Panel
Manual Account Linking (CLI)
If you need to manually link an existing user to an SSO identity, use the PostgreSQL database directly:
# Connect to database
docker exec -it pediatric-ai-scribe-postgres psql -U pedscribe -d pedscribe
# Link user by setting their oidc_sub
UPDATE users
SET oidc_sub = 'provider-sub-12345',
email_verified = true
WHERE email = 'doctor@example.com';
Finding the oidc_sub value:
The oidc_sub is the unique identifier from your OIDC provider (usually a UUID or numeric ID). To find it:
- Have the user attempt SSO login once
- Check the application logs for their
subclaim:[OIDC] User logged in: sub=abc-123-def, email=doctor@example.com - Use that
subvalue in the UPDATE statement
Security Considerations
HTTPS Required in Production
OIDC requires HTTPS for security. Ensure your APP_URL uses https://:
APP_URL=https://scribe.example.com
Client Secret Protection
The client secret is stored encrypted in the database. The admin UI masks it after saving (shows ••••••••1234).
Never commit the client secret to Git or share it publicly.
IP Allowlisting (Optional)
To restrict SSO to specific networks (e.g., hospital VPN):
- Set Allowed IPs in admin settings to comma-separated CIDR ranges:
10.0.0.0/8, 192.168.1.0/24 - Users outside these ranges will see an error when attempting SSO
Disable Local Password Login
Once SSO is working, you can optionally disable traditional email/password login:
- In Admin Settings, enable Disable Local Auth
- The login page will only show the SSO button
- Admins can still use the CLI to reset passwords if needed
Warning: Only disable local auth after confirming all users can access SSO. Keep one admin password as backup.
Troubleshooting
"SSO is not enabled" error
- Verify Enabled is set to
truein admin settings - Check application logs for OIDC configuration errors
"Invalid state" or "Expired" error
- The OIDC flow timed out (5 minute window)
- Try logging in again
- If persistent, check server time synchronization
"No email claim" error
Your OIDC provider didn't return an email address. Ensure:
- The
emailscope is requested (default:openid email profile) - Your provider is configured to release email claims
- The user's account has an email address set
Email Mismatch
If a user has different emails in the app vs. SSO provider:
Option 1: Update app email to match SSO
UPDATE users SET email = 'new-email@example.com' WHERE id = 123;
Option 2: Update SSO provider email to match app (Provider-specific — consult your IdP documentation)
Callback URL Not Working
Double-check the redirect URI in your OIDC provider settings matches exactly:
https://your-domain.com/api/auth/oidc/callback
Common mistakes:
- Missing
https:// - Trailing slash (don't include it)
- Wrong domain (must match
APP_URLin.env)
Provider-Specific Examples
PocketID
Issuer URL: https://id.pockethost.io
Client ID: (from PocketID app settings)
Client Secret: (from PocketID app settings)
Redirect URI: https://your-domain.com/api/auth/oidc/callback
Keycloak
Issuer URL: https://keycloak.example.com/realms/medical
Client ID: pediatric-scribe
Client Secret: (from Credentials tab)
Redirect URI: https://your-domain.com/api/auth/oidc/callback
Azure AD / Entra ID
Issuer URL: https://login.microsoftonline.com/{tenant-id}/v2.0
Client ID: (Application ID from Azure)
Client Secret: (from Certificates & secrets)
Redirect URI: https://your-domain.com/api/auth/oidc/callback
Note: Azure requires app registration in Azure Portal first.
Okta
Issuer URL: https://{your-okta-domain}.okta.com
Client ID: (from Okta application settings)
Client Secret: (from Okta application settings)
Redirect URI: https://your-domain.com/api/auth/oidc/callback
Google (Workspace or Gmail)
Issuer URL: https://accounts.google.com
Client ID: (from Google Cloud Console)
Client Secret: (from Google Cloud Console)
Redirect URI: https://your-domain.com/api/auth/oidc/callback
Note: Google requires OAuth consent screen configuration.
Environment Variables (Alternative to UI Config)
For deployment automation, you can set OIDC config via environment variables instead of the admin UI:
# .env file
OIDC_ENABLED=true
OIDC_ISSUER=https://id.example.com
OIDC_CLIENT_ID=my-client-id
OIDC_CLIENT_SECRET=my-client-secret
OIDC_BUTTON_LABEL=Sign in with PocketID
OIDC_DISABLE_LOCAL_AUTH=false
Note: UI settings take precedence over environment variables. If set in both places, the database values are used.
HIPAA Compliance Notes
OIDC does not transmit PHI to the identity provider. Only authentication-related data (email, name) is exchanged.
For HIPAA compliance:
- Ensure your OIDC provider has appropriate safeguards
- Use a self-hosted provider (Keycloak, PocketID) within your secure network
- Or use a HIPAA-compliant SaaS provider with a BAA
- Enable audit logging for all SSO login events (automatically logged in
audit_logtable)
Audit Logging
All SSO login events are logged in the audit_log table:
SELECT * FROM audit_log WHERE action = 'login_oidc' ORDER BY created_at DESC;
Logged fields:
- User ID
- Action:
login_oidc - IP address
- Details: Issuer URL
- Timestamp
Support
For issues specific to:
- This application: Check application logs with
docker logs pediatric-ai-scribe - Your OIDC provider: Consult provider documentation (PocketID, Keycloak, Azure, etc.)
- Network/TLS issues: Verify
APP_URLmatches your reverse proxy configuration
Common log locations:
# Application logs
docker logs pediatric-ai-scribe
# PostgreSQL logs
docker logs pediatric-ai-scribe-postgres