Skip to main content

Configuring Login and Registration Fields

The fields on the registration page and on the attribute-based login page are generated from the realm's User Profile configuration in Keycloak. One User Profile attribute produces one form field; the attribute's annotations decide how that field is rendered. The same configuration drives both pages.

To create an attribute, see Adding User Attributes to Keycloak.


Where the configuration lives

Realm settingsUser profile → select or create an attribute.

Settings that apply to the whole page rather than to one field are realm attributes, edited in the Admin Portal under the election event's Keycloak realm attributes. That editor lists the attributes a realm has, not the ones it supports, so each environment's default event realm configuration should carry them at their defaults — otherwise an election manager has no way to discover them:

Realm attributeDefault
credential-field-positionLAST
credential-input-policystandard
credential-input-patterndddd-dddd-dddd-dddd
credential-input-placeholderd
login-validation-policyBROWSER
voter-certificate-policydisabled

An attribute left unset behaves as its default, so seeding them changes nothing except what the editor shows.

Setting groupControls
General (name, display name, required)Field identity, label, and whether it is mandatory
AnnotationsInput type, placeholder, helper text, limits, option labels
ValidationsServer-side rules, and the option list for choice fields

Attribute names must match those used in voter import files, the Admin Portal's Voters tab, and the authenticator's User attributes to match list. Renaming an attribute does not rename it in existing user records.


Which pages use which attributes

PageAttributes rendered
RegistrationEvery User Profile attribute in scope for registration, in the order User Profile lists them
Login, standard username + passwordNone — username and password only
Login, attribute-based (Multi-Attribute + Password Form)Only the attributes in the authenticator's User attributes to match

Setting up attribute-based login, including its matching, ambiguity and abuse-control settings, is covered in Logging In Without a Username (Attribute + Password).

An attribute in User attributes to match that is not declared in User Profile renders as a plain text field. Its attribute name is used as a message key and falls back to the raw name when no translation exists. It is always mandatory to match.

Matching compares one value per attribute. On the attribute-based login page, a multiselect declaration therefore renders as a single-selection list and multiselect-checkboxes renders as radio buttons. Registration keeps the configured multi-value control.


Input types

Set the inputType annotation (Input type in the console).

inputTypeRenders asWhere it applies
(not set) or textPlain text inputBoth
textareaMulti-line text boxBoth
selectDropdown with an empty first optionBoth
multiselectMultiple-selection listRegistration only
select-radiobuttonsOne radio button per optionBoth
multiselect-checkboxesOne checkbox per optionRegistration only
html5-dateNative date pickerBoth
html5-telPhone-number widget with country selectorBoth
html5-email, html5-number, html5-url, …The corresponding native HTML5 inputBoth

Any html5- prefixed value becomes that HTML5 input type.

Date values must be stored as YYYY-MM-DD (e.g. 1990-01-05). Matching at login fails if imported data uses another format.


Labels and translations

Display name is the label shown above the input:

  • Literal text (Date of birth) — the same in every language.
  • A translation key (${dateOfBirth}) — resolved per language.

Define translation keys under Realm settingsLocalizationRealm overrides.


Helper text

AnnotationEffectWhere it applies
inputHelperTextBeforeText above the input, under the labelBoth
inputHelperTextAfterText below the inputBoth

Both accept literal text or a translation key, and both render on the registration page and the attribute-based login page.


Text and number settings

AnnotationEffectWhere it applies
inputTypePlaceholderPlaceholder textBoth
inputTypePatternRegular expression enforced by the browserBoth
inputTypeSizeVisible width in charactersBoth
inputTypeMinlength / inputTypeMaxlengthMinimum / maximum charactersBoth
inputTypeMin / inputTypeMaxMinimum / maximum value or dateBoth
inputTypeStepStep increment for numeric and date inputsBoth
inputTypeCols / inputTypeRowsText area dimensionsBoth

Date inputs are capped at 9999-12-31 unless inputTypeMax sets another maximum. Browser-side settings are a usability aid; use Validations for rules that must be enforced.


Option lists

For select, multiselect, select-radiobuttons and multiselect-checkboxes, options come from a validator:

  1. Under Validations, Add validatoroptions.
  2. Add each option value (e.g. M, F).

The option value is what gets stored. To display something else:

AnnotationEffectWhere it applies
inputOptionLabelsMap of option value → label, e.g. {"M": "Male", "F": "Female"}. Values may be translation keys.Both
inputOptionLabelsI18nPrefixEach option is translated as prefix.optionValue (e.g. sex.M)Both
inputOptionsFromValidationTake options from a different named validatorBoth

Dependent dropdowns

filterSelectAttribute, set on the controlling attribute with the dependent field's id as its value, narrows the dependent dropdown to options whose value contains the selected value, and preselects the first match. Option values must embed the controlling value (province 08, municipalities 08001, 08002). On attribute-based login, the dependent field must also be in User attributes to match.

Enabling and disabling other fields

On radio-button and checkbox attributes:

AnnotationEffectWhere it applies
disableAttributeTicking the option makes the named field read-only and clears itRegistration only
disableElementTicking the option disables the named fieldRegistration only

Other annotations

AnnotationEffectWhere it applies
defaultInitial value. Registration only; ignored on the attribute-based login form.Registration only
confirmRenders a second input for the same attribute. The value is the confirmation field's label.Registration only
html-attribute:<name>Sets an arbitrary HTML attribute, e.g. html-attribute:autocomplete = bday. Applies to text and HTML5 inputs only — dropdowns, radio buttons, checkboxes and text areas ignore it.Registration only
hidden = trueThe attribute is not rendered on the registration page. It is still stored and still usable for matching.Registration only

The Deferred Registration User Creation form action's Hidden Profile Attributes setting hides a comma-separated list of attributes from the registration form and ignores them if User Profile marks them required.


Autofill and the login page

The attribute-based login page sets autocomplete="off" on every match field and ignores User Profile html-attribute:autocomplete annotations. Failed match values are also not placed back in the page. These are deliberate shared-device protections for fields such as date of birth, national ID and phone number. Browsers may still apply their own autofill heuristics, so autocomplete="off" is a request rather than a privacy guarantee.


Phone number fields

inputType = html5-tel renders an international phone-number widget: country selector with dial code, per-country placeholder formatting, and an initial country guessed from the browser timezone. The submitted value is the full international number, stored under the attribute's own name. If inputTypePattern is configured, the browser checks it against that normalized full number rather than the national-format value visible beside the separate dial code.


Required fields

An attribute's Required field toggle marks it mandatory. On the registration page a required attribute gets an asterisk and is enforced by the browser and the server.

On the attribute-based login page, the authenticator's Honor User Profile required attributes setting governs the fields in User attributes to match:

SettingBehavior
Off (default)Every listed attribute is mandatory
OnEach field follows its own Required field setting. Non-required fields may be left blank, and matching proceeds on the attributes that were filled in

An all-blank submission always fails. An attribute not declared in User Profile stays mandatory.

Asterisks and the "Required fields" notice appear only when at least one field is optional, since marking every field would distinguish nothing. When they appear, the password or PIN is marked too.

⚠️ Enabling this widens who a login attempt can match: leaving nationalId blank matches every voter with the submitted dateOfBirth, leaving the password as the only narrowing factor. See Denial-of-Service Considerations.


Login hints are governed by two settings. The Deferred Registration User Creation form action's Prefill Parameters Policy is the master switch:

  • IGNORE (default) — login hints never prefill.
  • ACCEPT — validated hints may prefill, subject to the per-attribute policy.

Per attribute, the loginHintPrefillPolicy annotation:

ValueEffectWhere it applies
(not set) or EDITABLEPrefilled, and the voter may change itRegistration only
READ_ONLYPrefilled and locked; a changed value is rejectedRegistration only
IGNORENever prefilledRegistration only

A locked value is still submitted, including for dropdowns, radio buttons and checkboxes. Password fields, attributes annotated hidden, and attributes rendered invisible or uneditable by html-attribute: annotations or inline styles are never prefilled.

On the login page the username field is governed instead by the realm attribute loginHintUsernamePolicy (EDITABLE or READ_ONLY).


Validation

Annotations and validators are separate mechanisms and are enforced in different places.

Declared asWhat it doesRegister formLogin form
Annotation (inputTypePattern, inputTypeMaxlength, inputTypeMin/Max)Rendered as an HTML attribute, checked by the browser before submittingAppliesApplies
Validator (length, pattern, email, options, …)Checked on the server after submittingApplies, with a message beside the fieldIgnored

The attribute-based login page never runs User Profile validators: it matches the submitted values against voter records and answers with a single generic message. A validator declared on a match attribute has no effect there — it neither constrains the input nor rejects it.

Only the annotation limits typing. A length validator with max: 9 lets a voter type any number of characters and rejects the value afterwards; inputTypeMaxlength = 9 stops the input at nine. To limit typing and enforce the limit, declare both.

The options validator is the exception: both forms read it to build the choices for select, radio and checkbox fields, so it is load-bearing for rendering on both.

Who reports invalid formats on the login page

login-validation-policyEffect
BROWSER (default)The browser checks the constraint attributes and blocks submission, showing its own message beside the offending field
SERVER_ONLYThe form carries novalidate; submission always reaches the authenticator, which answers with the generic message

Browser messages come from the browser's language, not the realm's, and only one field is reported at a time. SERVER_ONLY removes them. The annotations stay in place either way: required fields are still announced by assistive technology, typing limits still apply, and the date picker is still bounded.

The structured PIN validates its own format in either mode, in the page's language, beside the field.


The password and PIN field

The password field is not a User Profile attribute; both pages add it themselves. These annotations apply to the registration form, where the password box sits underneath a chosen attribute:

AnnotationEffectWhere it applies
showPasswordAfterThisPosition of the password box. Defaults to after username (or email when used as username). Set false on that attribute to suppress it, or true on another attribute to move it. Always wins over credential-field-position.Registration only
passwordHelperTextBefore / passwordHelperTextAfterText above / below the password boxRegistration only
passwordStrengthBarPassword-strength meter. Registration only.Registration only

Putting the credential first

By default the password or PIN box sits after the identity fields. Set the realm attribute credential-field-position to FIRST to put it above them, with the page's initial focus on it — useful where a PIN from a voter letter is the primary thing being entered.

ValueEffect
LAST (default)Credential after the fields, focus on the first field
FIRSTCredential before the fields, focus on the credential

It applies to the attribute-based login page and to the registration form, not to the ordinary username and password login page. On the registration form an attribute declaring showPasswordAfterThis keeps its placement and this setting is ignored.

Structured PIN input

Renders the password box as fixed-length digit groups. It remains the voter's ordinary Keycloak password, and applies to the login page and to the registration form in login mode with a password field. Set credential-input-policy to structured to enable it; the pattern, placeholder, input behaviour and rollout steps are covered in Structured PIN login.


Other features that change these pages

Login page

FeatureConfigured withEffect
Attribute-based loginMulti-Attribute + Password Form authenticatorReplaces the username field with User Profile attribute fields
Structured PINcredential-input-* realm attributesPassword box becomes fixed-length digit groups
Locked usernameRealm attribute loginHintUsernamePolicy = READ_ONLYUsername is prefilled and read-only
Digital certificate loginRealm attribute voter-certificate-policy = enabledShows the digital-certificates provider button; hidden while disabled
Other identity providersKeycloak Identity providersEach enabled provider adds a button below the form
OID4VP (digital wallet)OID4VP identity providerUses its own QR / wallet page
IdP-initiated SSOSAML/OIDC identity providerLogin page is skipped
Remember meRealm setting Remember meAdds the checkbox
Forgot passwordRealm setting Forgot passwordAdds the reset link
Registration linkRealm setting User registrationAdds the register link
Login with emailRealm settings Login with email / Email as usernameChanges the username field label
reCAPTCHAKeycloak reCAPTCHA authenticatorInvisible reCAPTCHA on submit

Registration page

FeatureConfigured withEffect
Login modeDeferred Registration User Creation, Form Mode = LOGINRenders as a login form: no password confirmation, no strength bar, no back-to-login link
Password fieldSame form action, Password RequiredWhether a password box is rendered
Hidden attributesSame form action, Hidden Profile AttributesRemoves the listed attributes
Login-link prefillingSame form action, Prefill Parameters PolicySee Prefilled values
Terms and conditionsKeycloak Terms and Conditions required actionAdds the acceptance checkbox
reCAPTCHAKeycloak reCAPTCHA authenticatorAdds the reCAPTCHA widget
Identity providersKeycloak Identity providersProvider buttons shown in login mode only

Both pages

FeatureConfigured withEffect
LanguagesRealm attributes language_detection_policy, forced_language_code, and enabled localesInitial language and the language selector
Labels and messagesRealm settingsLocalizationRealm overridesAny label or message, per language
BrandingElection event theme settingsLogo, colors and layout