User Management
Create user accounts, assign roles, and manage access through Keycloak, the system's OIDC identity provider.
Checklist
- Access the Keycloak admin console
- Create the first admin user in the "zol" realm
- Assign the
adminrealm role - Verify login through the frontend
- Verify admin access to the management dashboard
Keycloak Admin Console
The Keycloak admin console is available on the server at port 8080 (localhost only). Access it via SSH tunnel:
# Open an SSH tunnel from your local machine
ssh -L 8080:127.0.0.1:8080 deploy@YOUR_SERVER_IP
# Then open in your browser:
# http://localhost:8080/admin
Login with the Keycloak admin credentials defined in .env.prod:
| Variable | Default |
|---|---|
KEYCLOAK_ADMIN | admin |
KEYCLOAK_ADMIN_PASSWORD | Set in .env.prod |
The Keycloak admin account is a system-level account for managing the identity provider itself. It is separate from application-level admin users who manage crawls, diagnostics, and settings within the ZOL RAG application.
Realm Configuration
The system uses the "zol" realm, which is automatically imported on first startup from the realm export file at scripts/keycloak/zol-realm.json. The realm defines:
| Setting | Value |
|---|---|
| Realm name | zol |
| Frontend client | zol-rag-frontend (public, PKCE) |
| Backend client | zol-rag-backend (confidential) |
| Token endpoint | /realms/zol/protocol/openid-connect/token |
Create a User
- Open the Keycloak admin console and select the "zol" realm (top-left dropdown).
- Navigate to Users in the left sidebar.
- Click Create new user.
- Fill in the required fields:
- Username: e.g.,
admin@zol.be - Email: e.g.,
admin@zol.be - First name and Last name
- Email verified: toggle ON
- Username: e.g.,
- Click Create.
- Go to the Credentials tab and click Set password.
- Enter the password, confirm it.
- Set Temporary to OFF (unless you want the user to change password on first login).
Assign the Admin Role
- Navigate to the user's detail page.
- Go to the Role mapping tab.
- Click Assign role.
- Filter by realm roles and select
admin. - Click Assign.
The application checks for the admin realm role in the JWT token's realm_access.roles claim. Users without this role have standard user permissions.
Roles
| Role | Permissions |
|---|---|
user | Search queries, view results (default for all authenticated users) |
admin | All of user + crawl management, diagnostics, user management, settings |
All authenticated users automatically receive the user role. Only the admin role needs to be explicitly assigned.
Verify Login
Via Frontend
Navigate to the application URL (e.g., https://test.medchat.health). The frontend uses @react-keycloak/web with the KeycloakProvider and will redirect to the Keycloak login page automatically for protected routes.
Via API (Token Acquisition)
# Obtain an access token from Keycloak
TOKEN=$(curl -s -X POST \
"https://YOUR_DOMAIN/realms/zol/protocol/openid-connect/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password" \
-d "client_id=zol-rag-frontend" \
-d "username=admin@zol.be" \
-d "password=YOUR_PASSWORD" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
# Verify token works — check current user info
curl -s https://YOUR_DOMAIN/api/v1/auth/me \
-H "Authorization: Bearer $TOKEN" | python3 -m json.tool
A successful response includes the user's email, name, and roles (including admin if assigned).
JWT Token Lifecycle
| Parameter | Default | Description |
|---|---|---|
| Access token lifespan | 5 minutes | Short-lived, used for API requests |
| Refresh token lifespan | 30 minutes | Used to obtain new access tokens |
| SSO session idle | 30 minutes | Idle timeout for the SSO session |
| SSO session max | 10 hours | Maximum duration of an SSO session |
The frontend automatically handles token refresh via the Keycloak JavaScript adapter. The backend validates tokens using python-jose by verifying the signature against Keycloak's JWKS endpoint (/realms/zol/protocol/openid-connect/certs).
Password Reset
Password resets are managed entirely through Keycloak:
- Admin-initiated: In the Keycloak admin console, navigate to the user, go to Credentials, and click Reset password.
- Self-service (if configured): Enable the "Forgot password" flow in the realm's Login settings. This requires SMTP configuration in Keycloak for sending reset emails.
# To configure SMTP for self-service password reset:
# Keycloak Admin Console → Realm Settings → Email → Configure SMTP server
Creating Additional Users
Additional users can be created through:
- Keycloak admin console — follow the same steps as above.
- Keycloak REST API — for programmatic user creation:
# Get an admin token
ADMIN_TOKEN=$(curl -s -X POST \
"http://localhost:8080/realms/master/protocol/openid-connect/token" \
-d "grant_type=password" \
-d "client_id=admin-cli" \
-d "username=admin" \
-d "password=YOUR_KEYCLOAK_ADMIN_PASSWORD" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
# Create a new user
curl -s -X POST \
"http://localhost:8080/admin/realms/zol/users" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"username": "user@zol.be",
"email": "user@zol.be",
"firstName": "New",
"lastName": "User",
"enabled": true,
"emailVerified": true,
"credentials": [{
"type": "password",
"value": "THEIR_PASSWORD",
"temporary": false
}]
}'
Public Endpoints
The following endpoints bypass authentication entirely and do not require a Keycloak token:
- Feedback submission — allows anonymous user feedback
- WebSocket query endpoint — public chat interface for hospital visitors
- Health check (
GET /health) — infrastructure monitoring
Security Notes
- Authentication uses Keycloak OIDC with JWT Bearer tokens
- Access tokens are validated against Keycloak's JWKS endpoint (public key verification)
- The backend uses
get_current_userandrequire_adminFastAPI dependencies for route protection - Failed login attempts are rate-limited by Keycloak's brute force detection (configurable in realm settings)
- All tokens are signed with RS256 (asymmetric keys managed by Keycloak)
- The Keycloak admin console is bound to
127.0.0.1only — accessible via SSH tunnel
Architectural Evolution
Prior to March 2026, the system used a legacy cookie-based authentication system with bcrypt password hashing. This was replaced by Keycloak OIDC to meet GDPR Article 25 requirements and provide enterprise-grade identity management. The migration to Keycloak also enables future integration with hospital-internal identity providers (e.g., Active Directory federation) without application code changes.
Next: Monitoring →