Authentication Server
This folder sets up a local authentication server using Keycloak for development and testing purposes.
Keycloak
Getting Started at developer environment
Start the development environment using the Aspire Dashboard:
Once running, access Keycloak Admin UI using the dashboard. Login with:
- Username: admin
- Password: keycloak-MySecretP@sswOrd
To configure a web client and an API client, follow the official guide: Keycloak - Getting Started with Docker
Getting Started at production environment
In production, Keycloak is deployed as a Kubernetes StatefulSet via the Helm chart. It is exposed at authentication.<domain> through the Traefik ingress with TLS.
- Set the admin credentials in
values.production.yamlunderkeycloak.usernameandkeycloak.password. - Deploy the chart — Keycloak will start and create a fresh realm on first boot.
- Access the Admin UI at
https://authentication.<domain>and log in with the credentials above. - Follow the same configuration steps as the developer environment: create the clients, add the audience scope, configure the roles claim, and create the
AdministratorandUserroles.
💡 The realm name and client IDs are controlled by
keycloak.realm,admin.oidc.clientId, andportal.oidc.clientIdinvalues.yaml. Make sure the values in Keycloak match these exactly.
Add Audience Attribute (for JWT validation)
To include the correct aud (audience) claim in your tokens:
- Go to Client Scopes in the Keycloak Admin UI.
- Click Create to add a new client scope (e.g.,
audience-api). - Navigate to the Mappers tab of the client scope.
- Click Create.
- Set Mapper Type to
Audience. - Set Name to
audience-api-mapper. - Set Included Client Audience to your target client ID (e.g.,
api-client). - Enable Add to access token and Add to ID token.
- Click Save.
- Go to Clients, select the client that should include this audience.
- Open the Client Scopes tab.
- Add your new client scope as either Default or Optional.
💡 This ensures the
audfield in the JWT token includes the specified client audience (e.g.,api-client), which is commonly required for API-side JWT validation.
Add Roles
Byakko requires two realm roles: Administrator and User. The token claim name must be roles so the API and Blazor apps can read them.
Create the roles
- Go to Realm roles in the Keycloak Admin UI.
- Click Create role.
- Set Role name to
Administratorand click Save. - Repeat to create the
Userrole.
Set the Token Claim Name to roles
By default Keycloak maps realm roles under realm_access.roles. Change it to a flat roles claim:
- Go to Client Scopes and open roles.
- Open the Mappers tab and click realm roles.
- Set Token Claim Name to
roles. - Enable Add to access token, Add to ID token, and Add to userinfo.
- Click Save.
Assign a role to an account (optional)
- Go to Users and open the account.
- Open the Role mapping tab.
- Click Assign role, select
AdministratororUser, and confirm.
Add Grafana Client
Grafana authenticates against Keycloak using a confidential OAuth2 client named grafana-client. Only users with the Administrator role can sign in — non-admins are rejected by the strict role attribute check.
- Go to Clients in the Keycloak Admin UI and click Create client.
- Set Client ID to
grafana-clientand click Next. - Enable Client authentication (this makes it a confidential client) and click Next.
- Set Valid redirect URIs to
https://grafana.<domain>/login/generic_oauth. - Click Save.
- Open the Credentials tab and copy the Client secret — use it as the
GRAFANA_KEYCLOAK_CLIENT_SECRETenvironment secret in the deployment pipeline. - Go to Clients → grafana-client → Advanced tab → Authentication flow overrides → set Browser Flow to
administrator-only-browser→ Save.
After this, non-Administrator users receive "You don't have access to this application" from Keycloak before reaching Grafana.
💡 The
administrator-only-browserflow must be created first — see Restrict Headlamp login to Administrators only under Step 6 — Connect Headlamp with Keycloak in the Kubernetes guide for the step-by-step flow setup. The same flow is reused here.
💡 The
rolesclaim must already be mapped to the flatrolestoken claim (see Set the Token Claim Name toroles) — Grafana's role attribute pathcontains(roles[*], 'Administrator') && 'Admin' || ''depends on it.
Add pgAdmin Client
pgAdmin authenticates against Keycloak using a confidential OAuth2 client named pgadmin-client. Only users with the Administrator role can sign in — non-admins are rejected at the Keycloak level before reaching pgAdmin.
- Go to Clients in the Keycloak Admin UI and click Create client.
- Set Client ID to
pgadmin-clientand click Next. - Enable Client authentication (this makes it a confidential client) and click Next.
- Set Valid redirect URIs to
https://database.<domain>/oauth2/authorize. - Click Save.
- Open the Credentials tab and copy the Client secret — use it as the
PGADMIN_KEYCLOAK_CLIENT_SECRETenvironment secret in the deployment pipeline. - Go to Clients → pgadmin-client → Advanced tab → Authentication flow overrides → set Browser Flow to
administrator-only-browser→ Save.
After this, non-Administrator users receive "You don't have access to this application" from Keycloak before reaching pgAdmin.
💡 The
administrator-only-browserflow must be created first — see Restrict Headlamp login to Administrators only under Step 6 — Connect Headlamp with Keycloak in the Kubernetes guide for the step-by-step flow setup. The same flow is reused here.
Enable Login Settings
- Go to Realm settings in the Keycloak Admin UI.
- Open the Login tab.
- Enable the following options:
- User registration — allows new users to self-register
- Forgot password — shows a password reset link on the login screen
- Remember me — lets users stay logged in across browser sessions
- Verify email — requires users to verify their email address after registration
- Click Save.
💡 In the developer environment, User registration is enabled automatically via
MadWorld-realm.json. In production, enable it manually after first deploy.
Configure Session Timeouts
Byakko uses a 1-day session for normal logins and a 7-day session when users tick Remember me.
- Go to Realm settings in the Keycloak Admin UI.
- Open the Sessions tab.
- Set the following values:
| Setting | Value |
|---|---|
| SSO Session Idle | 1 day |
| SSO Session Max | 1 day |
| SSO Session Idle Remember Me | 7 days |
| SSO Session Max Remember Me | 7 days |
- Click Save.
💡 In the developer environment these values are set automatically via
MadWorld-realm.json. In production, apply them manually after the first deploy.
Terms and Conditions
Byakko shows a Terms and Conditions acceptance screen (linking to /user-agreement) before users can complete their first login. This is implemented via a Keycloak Required Action and a custom byakko login theme.
How it works
- The
byakkologin theme overrides only thetermsTextmessage key. All other UI inherits fromkeycloak.v2. - The Required Action
TERMS_AND_CONDITIONSintercepts the login flow and presents the acceptance screen. defaultAction: truemeans every user (new and existing) must accept once.
Developer environment (Aspire)
This is configured automatically:
MadWorld-realm.jsonhas"loginTheme": "byakko"andTERMS_AND_CONDITIONSenabled withdefaultAction: true.- The theme files are bind-mounted from
src/MadWorldEU.Byakko.Aspire/Configurations/KeyCloak/themes/into the Keycloak container.
To change the terms link, edit themes/byakko/login/messages/messages_en.properties and restart the Keycloak container.
Production environment (Helm)
The theme files are injected via the keycloak-theme-byakko ConfigMap in templates/keycloak.yaml. The termsText URL is derived from {{ .Values.ingress.domain }} and resolves to https://byakko.dev/user-agreement.
To enable the Required Action in a fresh production realm:
- Go to Authentication → Required Actions in the Keycloak Admin UI.
- Find Terms and Conditions and toggle Enabled on.
- Toggle Default Action on so existing users are prompted on next login.
Enable localization in production
The Helm chart injects translated termsText for English, Dutch, and Japanese, but Keycloak will only use them once localization is enabled at the realm level:
- Go to Realm Settings → Localization tab.
- Toggle Internationalization on.
- Add
en,nl, andjaunder Supported Locales. - Set Default Locale to
en. - Click Save.
💡 In the developer environment this is configured automatically via
MadWorld-realm.json. In production it must be done manually after first deploy.
Configure Email
Keycloak uses an SMTP server to send verification, password reset, and other system emails. To configure it:
- Go to Realm settings in the Keycloak Admin UI.
- Open the Email tab.
- Fill in the following fields:
- From — The sender email address (e.g.
noreply@example.com) - From display name — The human-readable sender name shown in email clients (e.g.
Byakko) - Host — The SMTP server hostname (e.g.
smtp.example.com) - Port — The SMTP port (e.g.
587for StartTLS,465for SSL) - Enable StartTLS — Toggle on when using port 587 to upgrade the connection to TLS
- Username — The SMTP account username used to authenticate
- Password — The SMTP account password used to authenticate
- From — The sender email address (e.g.
- Click Save, then use the Test connection button to verify Keycloak can reach the mail server.
Test Login with Keycloak Using the Official Test App
You can verify that your Keycloak server is correctly issuing tokens (including the aud claim) by using Keycloak's official test app: