Keycloak Configuration - bcgov/eagle-dev-guides GitHub Wiki
Keycloak Configuration
Authentication configuration for EPIC applications using BC Government's Common Sign-In Service (CSS).
Overview
EPIC applications use Keycloak for authentication:
| Application | Client ID | Authentication |
|---|---|---|
| eagle-api | eagle-api-console |
Backend JWT validation |
| eagle-admin | eagle-admin-console |
Staff authentication (IDIR/BCeID) |
| eagle-public | None | No authentication (public website) |
Keycloak Endpoints:
- Dev/Test:
https://dev.loginproxy.gov.bc.ca/auth - Prod:
https://loginproxy.gov.bc.ca/auth - Realm:
eao-epic(shared across all EPIC applications)
Client ID Preservation Pattern
Problem
The /api/config endpoint returns the API's client ID (eagle-api-console), but eagle-admin needs its own (eagle-admin-console).
Solution
eagle-admin's ConfigService preserves KEYCLOAK_CLIENT_ID from env.js:
// eagle-admin/src/app/services/config.service.ts
const preservedClientId = this._config().KEYCLOAK_CLIENT_ID;
this._config.set({
...this._config(),
...apiConfig,
KEYCLOAK_CLIENT_ID: preservedClientId // Don't use API's value
});
Note: eagle-public does NOT use Keycloak - it's a public website with no authentication.
Helm Configuration
eagle-api Helm Values
# helm/eagle-api/values-dev.yaml
keycloak:
enabled: true
url: "https://dev.loginproxy.gov.bc.ca/auth"
realm: eao-epic
clientId: eagle-api-console
Deployment Template Injection
Keycloak variables are set directly in deployment (NOT via ConfigMap):
# helm/eagle-api/templates/deployment.yaml
{{- if .Values.keycloak.enabled }}
- name: SSO_ISSUER
value: "{{ .Values.keycloak.url }}/realms/{{ .Values.keycloak.realm }}"
- name: SSO_JWKSURI
value: "{{ .Values.keycloak.url }}/realms/{{ .Values.keycloak.realm }}/protocol/openid-connect/certs"
- name: KEYCLOAK_CLIENT_ID
value: {{ .Values.keycloak.clientId }}
- name: KEYCLOAK_URL
value: {{ .Values.keycloak.url }}
- name: KEYCLOAK_REALM
value: {{ .Values.keycloak.realm }}
- name: KEYCLOAK_ENABLED
value: "true"
{{- end }}
Production Configuration Override (eagle-admin)
Production Issue: Built-in env.js with Incorrect URL
Problem: eagle-admin container image built with dev Keycloak URL hardcoded:
// Wrong dev URL in built-in env.js
KEYCLOAK_URL: "https://dev.loginproxy.gov.bc.ca/auth"
Solution: Mount production env.js via ConfigMap
Create ConfigMap
oc create configmap eagle-admin-env-js \
--from-literal=env.js='window.globalThis = {
KEYCLOAK_URL: "https://loginproxy.gov.bc.ca/auth",
KEYCLOAK_CLIENT_ID: "eagle-admin-console",
API_LOCATION: "https://projects.eao.gov.bc.ca"
};' \
-n 6cdc9e-prod
Mount in DeploymentConfig
# Edit eagle-admin DeploymentConfig
oc edit dc eagle-admin -n 6cdc9e-prod
Add volume and volumeMount:
spec:
template:
spec:
containers:
- name: eagle-admin
volumeMounts:
- name: env-js-override
mountPath: /app/env.js
subPath: env.js
volumes:
- name: env-js-override
configMap:
name: eagle-admin-env-js
Result: Container loads production Keycloak configuration, ConfigService preserves KEYCLOAK_CLIENT_ID.
Troubleshooting
"Client not found" Error
Cause: Frontend is using wrong client ID
Diagnosis:
// In browser console (eagle-admin)
ConfigService.config().KEYCLOAK_CLIENT_ID
// Should be: "eagle-admin-console"
// If showing: "eagle-api-console" → Client ID preservation is broken
Fixes:
- Check ConfigService: Verify eagle-admin's ConfigService preserves
KEYCLOAK_CLIENT_IDfrom env.js - Check Image Version: Older images may lack ConfigService fix - redeploy with latest test image
- Check ConfigMap: In production, verify
eagle-admin-env-jsConfigMap exists and is mounted
"Page not found on Red Hat Single Sign-On"
Cause: Realm doesn't exist or incorrect URL
Diagnosis:
# Verify realm exists
curl https://dev.loginproxy.gov.bc.ca/auth/realms/eao-epic/.well-known/openid-configuration
Token Validation Failures
Diagnosis:
# Check eagle-api logs for JWT errors
oc logs -n 6cdc9e-dev deployment/eagle-api | grep -i jwt
# Verify JWKS endpoint
curl https://dev.loginproxy.gov.bc.ca/auth/realms/eao-epic/protocol/openid-connect/certs
All Admin Users Redirected to "Email for access" Page
Symptom: Every staff member (regardless of their actual roles) is shown the "You need to provide your email address for access" page immediately after login. The browser URL shows /not-authorized.
Root cause: CSS (BC Government Common Sign-In Service) removed roles from the Keycloak realm's default client scopes. As a result, JWTs are issued without realm_access.roles, so isAuthorized() in keycloak.service.ts always evaluates to false and every user is redirected.
Diagnosis:
# Decode the JWT a staff user receives and look for realm_access
# (Use jwt.io or browser DevTools → Application → Local Storage → keycloak token)
# Missing: "realm_access": {"roles": [...]} means roles scope was removed
Fix applied in eagle-admin v2.4.3: Explicitly request the roles scope in the Keycloak init call so it is always included regardless of CSS default scope configuration:
// eagle-admin/src/app/services/keycloak.service.ts
this.keycloakAuth.init({
onLoad: 'login-required',
pkceMethod: 'S256',
checkLoginIframe: false,
scope: 'openid roles' // ← explicit scope prevents CSS scope changes from locking out all users
});
If this symptom recurs after a CSS platform change, verify:
- The
scope: 'openid roles'line is present inkeycloakAuth.init() - The
eagle-admin-consoleKeycloak client still has therolesscope available (not deleted from the realm) - Contact CSS team if the
rolesscope has been removed at the realm level
Redirect URI Mismatch
Cause: Keycloak client doesn't have correct redirect URI configured
Fix: Contact CSS team to add redirect URI to client configuration:
- Dev:
https://eagle-dev.apps.silver.devops.gov.bc.ca/admin/* - Prod:
https://projects.eao.gov.bc.ca/admin/*
Related Pages
- Configuration Management - ConfigService pattern
- API Architecture - Backend authentication flow
- Troubleshooting - Common issues