Skip to main content

SSO Integration

One login for hrida-ai-studio and HridaOne — per-user data isolation via Keycloak.

When SSO is configured, employees sign in once through Keycloak. Both hrida-ai-studio and HridaOne trust the same realm, so the HR Agent can call HridaOne with the employee's own token — HridaOne's RBAC then decides exactly what that employee may see. Without SSO, the agent uses a service account instead.


Architecture​

┌─────────────────────────────────────────────────────────┐
│ Keycloak (shared realm, e.g. "hrida") │
│ Clients: hrida-ai-studio, hridaone │
└──────────────────────┬──────────────────────────────────┘
│ OIDC / JWT (RS256)
┌────────────┴──────────────────┐
▼ ▼
┌─────────────────┐ ┌──────────────────┐
│ hrida-ai-studio │ │ HridaOne HRMS │
│ (port 8080) │ │ (port 8081) │
│ OIDC login │ │ validates KC │
└────────┬────────┘ │ tokens natively │
│ per-user KC token └────────▲─────────┘
│ → Redis │
▼ │
hr-agent MCP tools ──── REST ────────────┘
Authorization: Bearer {user_kc_token}

For the step-by-step token lifecycle in chat and in workflow runs, see Architecture & Token Flow.


Data isolation by role​

HridaOne roleWhat the HR Agent can see / do
EmployeeOwn profile, leave balance, attendance, payslip; apply for own leave; raise tickets
ManagerAll of above + team members' leave and attendance
HR AdminAll of above + org-wide attendance dashboard, all employee data

The agent has no hard-coded data restrictions — the scope is entirely determined by the token presented to HridaOne.


1. Configure Keycloak​

Create or reuse a realm​

Both applications must use the same realm (for example hrida).

Register the clients​

hrida-ai-studio (skip if Studio already signs in through Keycloak)

  1. Clients → Create client, Client ID hrida-ai-studio, protocol openid-connect.
  2. Turn on Client authentication and Standard flow.
  3. Set Valid redirect URIs to https://<your-studio-domain>/oauth/oidc/callback.
  4. Copy the client secret from the Credentials tab.

hridaone

  1. Clients → Create client, Client ID hridaone, protocol openid-connect, Client authentication on.
  2. Set Valid redirect URIs to https://<your-hridaone-domain>/sso/callback (used by HridaOne's own SSO sign-in).
  3. Copy the client secret from the Credentials tab.

HridaOne accepts tokens issued to any client listed in KEYCLOAK_ALLOWED_CLIENT_IDS (default hridaone,hrida-ai-studio), so tokens Studio obtains at login work against HridaOne directly.

Map the tenant code into the token​

HridaOne reads the tenant (company) from the hrida_tenant_code claim — the claim name is fixed.

  1. Client scopes → profile → Mappers → Add mapper → By configuration → User Attribute.
  2. Set User Attribute and Token Claim Name to hrida_tenant_code, and enable Add to access token.
  3. Set the attribute on each user: Users → (user) → Attributes, key hrida_tenant_code, value = the tenant code in HridaOne (for example ACME).

Users that HridaOne creates in Keycloak, and users synced through an LDAP/AD provider that HridaOne provisions, get hrida_tenant_code set automatically. You still need the mapper from step 1 so the attribute reaches the token.

Check the token claims​

The realm's standard profile and email scopes provide sub, email, and name, which HridaOne uses for lookup and JIT provisioning.


2. Configure HridaOne​

HridaOne validates Keycloak tokens in KcJwtAuthenticationFilter. Set these environment variables:

VariableDescription
KEYCLOAK_ISSUER_URIRealm URL as HridaOne reaches it, e.g. http://keycloak:9090/realms/hrida. Leave empty to disable Keycloak auth.
KEYCLOAK_PUBLIC_ISSUER_URIPublic realm URL when it differs (e.g. https://keycloak.example.com/realms/hrida). Tokens whose iss matches either value are accepted.
KEYCLOAK_CLIENT_ID / KEYCLOAK_CLIENT_SECRETThe hridaone client
KEYCLOAK_ALLOWED_CLIENT_IDSClients whose tokens are accepted (default hridaone,hrida-ai-studio)

How the filter works​

  1. Reads the Authorization: Bearer header. RS256 tokens are treated as Keycloak tokens; HS256 tokens go to HridaOne's native login.
  2. Verifies the signature against Keycloak's public keys ({issuer}/protocol/openid-connect/certs, cached and refreshed on rotation).
  3. Checks iss against the issuer URIs and azp against KEYCLOAK_ALLOWED_CLIENT_IDS.
  4. Looks up the user by email — or JIT-provisions an EMPLOYEE under the tenant from hrida_tenant_code.
  5. Sets the security context so the request runs as that employee.

3. Configure hrida-ai-studio​

Point Studio's OAuth login at the same realm:

ENABLE_OAUTH_SIGNUP=true
OAUTH_CLIENT_ID=hrida-ai-studio
OAUTH_CLIENT_SECRET=<from-keycloak>
OPENID_PROVIDER_URL=https://<keycloak-host>/realms/hrida/.well-known/openid-configuration
REDIS_URL=redis://redis:6379/0

See SSO for all OAuth options. No other switch is needed: the HR Agent's Digital Employee filter and the workflow worker store the user's Keycloak token in Redis automatically.


4. Configure hrida-mcpo​

Turn on per-user tokens in the hr-agent entry of mcpo's config.json, and point it at the same Redis as Studio:

"env": {
  "HRIDAONE_API_URL": "http://hridaone:8081",
  "HRIDAONE_USE_PER_USER_TOKEN": "true",
  "REDIS_URL": "redis://redis:6379/0",
  "HRIDAONE_EMAIL": "hr-agent@yourcompany.com",
  "HRIDAONE_PASSWORD": "<service-account-password>"
}

Keep the service account credentials as a fallback for cron/webhook-triggered runs and users who signed in without Keycloak.


Token TTL and expiry​

ScenarioToken usedRedis TTL
User chats with the HR AgentUser's KC token (hrida:kc_token:{user_id})600 s, refreshed on each message
User starts a workflow runUser's KC token (hrida:kc_token:{run_id})WORKFLOW_MAX_TIMEOUT_SECONDS + 60 s
Cron or webhook trigger (no user session)Service account—
No per-user token foundService account—

The Redis TTL only controls how long the token is available. Keycloak's own Access Token Lifespan (5 minutes by default) decides how long HridaOne accepts it — raise it under Realm Settings → Tokens if long runs hit 401s.


Troubleshooting​

HR Agent returns data from the service account, not the user's own → The per-user token isn't being used. Check HRIDAONE_USE_PER_USER_TOKEN=true in mcpo, that the user signed in through Keycloak, and that the key exists: redis-cli keys "hrida:kc_token:*".

HridaOne returns 401 for KC tokens → The token's iss must match KEYCLOAK_ISSUER_URI or KEYCLOAK_PUBLIC_ISSUER_URI exactly, and its azp must be in KEYCLOAK_ALLOWED_CLIENT_IDS. Check HridaOne's logs for the rejection reason.

JIT provisioning fails or creates users in the wrong company → The hrida_tenant_code claim is missing or wrong. Decode the token and confirm the claim; add the mapper from Map the tenant code into the token.

Redis connection refused from mcpo → Redis must be reachable from the mcpo process. Set REDIS_URL in the hr-agent env block of config.json.

More cases: HR Agent Troubleshooting.


Hrida.ai is proprietary software of Zlabs Innovation. See the license for terms. © 2026 Zlabs Innovation.