Authentication
Native email / password
The default. A company registers, its Super Admin is created, and employees are given login access with credentials emailed to them.
| Endpoint | Purpose |
|---|---|
POST /api/auth/register | Company / user registration |
POST /api/auth/login | Email + password → JWT |
GET /api/auth/resolve-login-mode | Tells the client whether this address signs in natively or via SSO |
POST /api/auth/verify-login-otp · /resend-login-otp | Two-step login OTP |
POST /api/auth/forgot-password · /reset-password | Email-based password reset |
GET /api/auth/me · /validate | Current user, token validation |
JWTs are signed with JWT_SECRET (HS-family, 64+ char secret). The frontend stores the token and decodes exp locally to pre-empt expiry, but the server is the authority.
Keycloak SSO
Set the KEYCLOAK_* variables to switch a deployment (or specific tenants) to browser SSO. Leave them blank for SaaS mode / native auth only.
| Variable | Meaning |
|---|---|
KEYCLOAK_ISSUER_URI | Must match the iss claim in Keycloak tokens exactly |
KEYCLOAK_CLIENT_ID / KEYCLOAK_CLIENT_SECRET | The confidential HridaOne client |
KEYCLOAK_SSO_CALLBACK_URL | Registered redirect URI, matching the port binding exactly |
KEYCLOAK_ALLOWED_CLIENT_IDS | Client ids trusted to authenticate against HridaOne (checked against the token's azp) — e.g. hridaone,hrida-ai-studio |
KEYCLOAK_SSO_COOKIE_SECURE | true in production; false only for local HTTP dev |
The SSO flow lives under /sso — GET /sso/keycloak starts it, GET /sso/callback completes it, GET /sso/config reports whether SSO is available.
SSO-enforced tenants
A tenant with authProvider=SSO has its users provisioned into Keycloak through a separate service-account client (KEYCLOAK_ADMIN_CLIENT_ID / SECRET, holding only the manage-users realm role). A background job pull-syncs those companies on KEYCLOAK_SYNC_INTERVAL_MS, so directory changes propagate without a manual push.
LDAP
Two distinct, independent LDAP features:
Shared provisioning directory
An LDAP directory this app owns. With LDAP_PROVISIONING_ENABLED=true, registering a company creates ou=<CompanyName>,ou=companies,{LDAP_BASE_DN} with People, Groups and Departments sub-OUs. Groups get a matching cn= entry, kept in sync on rename. The OU is resolved through a stored name, not the mutable company code, so migrating a company's OU to match an existing enterprise directory never orphans provisioned entries.
Per-tenant LDAP / AD federation
A company can point HridaOne at its own LDAP or Active Directory through a Configure LDAP modal — entirely separate from the shared directory above. This is how an enterprise tenant authenticates against its existing corporate directory.
Deployment modes
| Mode | Auth posture |
|---|---|
| SaaS | Native email / password, optional login OTP |
| Enterprise | Typically Keycloak SSO + per-tenant LDAP, bundled with Hrida AI Studio |