What this is about
The CodamAI user interfaces have no login form of their own. When you sign in, you land on a page from Keycloak. How you get there is described in Sign in in the browser. This page is about the pages themselves: which ones exist, when they appear and where they lead.
A theme is the design of these pages. Keycloak builds every page from a template in the FreeMarker format (file extension .ftl) and fills it with texts from a language file. The CodamAI theme is called codamai and lives in the hub-login repository.
What a page looks like
Every page has two columns:
- Left the actual form: heading, a short intro sentence, the fields, messages and buttons.
- Right a product panel with a background image, the CodamAI modules and short value statements.
All texts are in messages_de.properties and messages_en.properties, including those of the product panel. A language picker appears at the top of the form as soon as internationalization is switched on in the realm and more than one language is offered.
The theme inherits from the stock keycloak theme (parent=keycloak). Pages it does not design itself, such as passkeys (WebAuthn), setting up a one-time code or “complete your profile”, therefore come with Keycloak’s standard layout, embedded in the CodamAI frame.
The page map
flowchart TD
APP["User interface<br/>/login"] --> L["Sign in<br/>login.ftl"]
L -- "password correct" --> OTP{"second factor<br/>set up?"}
OTP -- yes --> O["One-time code<br/>login-otp.ftl"]
OTP -- no --> PA{"required action<br/>open?"}
O --> PA
PA -- "set password" --> UP["New password<br/>login-update-password.ftl"]
PA -- "verify email" --> VE["Verify email<br/>login-verify-email.ftl"]
PA -- none --> BACK["back to the user interface<br/>with code"]
UP --> BACK
VE --> BACK
L -- "link “Forgot password”" --> RP["Forgot password<br/>login-reset-password.ftl"]
RP --> MAIL["Mail from Keycloak<br/>with link"]
MAIL --> UP
L -. "open too long" .-> EX["Page expired<br/>login-page-expired.ftl"]
EX --> L
Read it like this: the sign-in always starts in the user interface, which forwards from /login to Keycloak on its own. After the password and, if needed, the one-time code, Keycloak checks whether a required action is still open for the account. A required action is a step Keycloak demands before the first access, for example “set password”. Only when nothing is open any more does Keycloak send the person back to the user interface with the one-time code.
Which page comes when
| Page | Template | When it appears | Where next |
|---|---|---|---|
| Sign in | login.ftl | on every sign-in without an existing Keycloak session | one-time code, required action or back to the user interface |
| Username, then password | login-username.ftl, login-password.ftl | when the sign-in flow in the realm is switched to “username first” | like “Sign in” |
| Forgot password | login-reset-password.ftl | link “Forgot password?” on the sign-in page | Keycloak sends a mail with a link |
| New password | login-update-password.ftl | required action UPDATE_PASSWORD, link from the CIAS welcome mail or from the “forgot password” mail | back to the user interface |
| One-time code (OTP) | login-otp.ftl | the account has a second factor set up | required action or back |
| Verify email | login-verify-email.ftl | required action VERIFY_EMAIL in Keycloak | continues after the click in the mail |
| Page expired | login-page-expired.ftl | the sign-in page was open too long, or the browser went back | “Restart” or “Continue” |
| Error | error.ftl | Keycloak cannot continue the process, for example with an invalid link | “Back to application” if the client has a start address |
| Info | info.ftl | after a completed action, for example “account updated” | continue link to the application or to the next action |
| Confirm sign-out | logout-confirm.ftl | when signing out without an ID token | signed out after the click |
| Register | register.ftl | only if registration is switched on in the realm | Keycloak creates the account |
OTP means one-time password: a code from an authenticator app that is valid only once and only briefly.
What the realm settings show or hide
Some elements of the pages depend on switches in the realm. The theme checks them and shows the element only if the switch is on.
| Switch in the realm | shipped in cias-runtime | What happens on the sign-in page |
|---|---|---|
| resetPasswordAllowed | on | Link “Forgot password?” appears |
| registrationAllowed | off | no link “Register” |
| rememberMe | off | no checkbox “Remember me” |
| loginWithEmailAllowed | on | field is labelled “Username or email” |
| internationalizationEnabled | off | no language picker |
| verifyEmail | off | Keycloak does not require its own email verification |
The second column shows the realm file that cias-runtime ships under deploy/keycloak/import/. Another installation can set every switch differently.
The variants
When: The user interface forwards from /login to Keycloak, and there is no session there yet.
-
1User→Keycloakenters username or email and password
-
2KeycloakAre the details correct?
-
3Keycloakotherwise: the same page with an error message below the fields
-
4Keycloak→Browserredirect back to the user interface with code
Result: The BFF of the user interface exchanges the code for tokens, see Sign in in the browser.
When: The sign-in flow in the realm asks for the username first.
Keycloak first shows login-username.ftl, then login-password.ftl. The second page shows the username at the top, plus a link to start over with a different name. The link “Forgot password?” is on the password page.
Result: Same result as the one-step sign-in.
When: Someone clicks “Forgot password?”. The link only appears if resetPasswordAllowed is on.
-
1User→Keycloakenters username or email
-
2Keycloak→Emailsends a mail with a reset link
-
3User→Keycloakopens the link, sets a new password
Result: The mail comes from Keycloak, with its templates and the mail server setting in the realm, not through the CIAS mail templates.
When: The required action UPDATE_PASSWORD is open for the account, or someone opens a password link.
CIAS sets this required action when it activates an account from a registration, and adds a direct link to the welcome mail where possible. The page asks for the new password twice. The checkbox “Sign out from other devices” is preselected. If an application started the action itself, there is also “Cancel”.
Result: See Setting the password.
When: The account has a second factor, that is an authenticator app.
After the password, Keycloak asks for the code from the app. If several apps are set up, the person first picks which one to use. Setting up a second factor is a separate page that the theme takes over from the stock theme.
Result: Code correct → continue. Code wrong → the same page with an error message.
When: Keycloak itself requires a confirmation of the address (required action VERIFY_EMAIL, or verifyEmail in the realm).
The page says that a mail was sent to the address and offers a link to send it again. This page does not occur on the CIAS path: CIAS verifies the address itself, with its own link, and then marks it as verified in Keycloak.
Result: See Verify the email for the verification by CIAS.
When: The sign-in page was open too long, or the browser resubmitted an old page.
Two buttons: Restart starts the sign-in from the beginning, Continue tries to carry on at the current step.
Result: Not a system error, just an outdated page.
When: Keycloak cannot continue (error) or reports a completed action (info).
The error page shows Keycloak's message in a red box and, if the client has a start address, a button “Back to application”. The info page shows a message, if applicable the list of still open required actions, and a continue link.
Result: Typical case: a password link that was already used or has expired.
When: The user interface ends the Keycloak session without sending an ID token.
Keycloak asks whether you really want to sign out. With an ID token the question is skipped.
Result: See Signing out.
When: registrationAllowed is switched on in the realm. In the shipped realm file it is off.
The theme brings a page with first name, last name, email, if needed username, and password. Accounts created here bypass CIAS.
Result: At CodamAI, new accounts are created via Register and verify.
Adding the theme to Keycloak
The theme is static: FreeMarker templates, language files, a stylesheet and a small script (show password, language menu). The stylesheet resources/css/styles.css is built with Tailwind from src/main.css (npm run build).
- Put the folder
theme/codamaiinto Keycloak’s theme directory (/opt/keycloak/themes/codamai). - In the realm, select
codamaiunder Realm settings → Themes → Login theme.
The realm file from cias-runtime does not set a login theme. Without this selection, Keycloak shows its stock pages. The flow is the same.