Login Controller
By default, if you use standard authentication you will get a standard login window when navigating to the application. You can customize the login window by setting some controller properties or replacing it with a different controller altogether.
By default, a view named Login is used if present. As an example of a stand-alone login view, here is the entire content of a file named Login.yaml:
Controller: Login
BorderPanel:
NorthView:
Controller: HtmlPanel
Height: 180
Html: |
<div style="text-align: center">
<p/>
<p><img src="%IMAGE(main_logo)%"></img></p>
<p><b>Application Name</b></p>
<p style="margin-left: 10px">A link <a href="mailto:one@domain.com">one@domain.com</a><br>
Another link <a href="mailto:two@domain.com">two@domain.com</a><br><br>
</p>
<p/>
</div>
SouthView:
Controller: HtmlPanel
Height: 60
Html: |
<div style="text-align: center; font-size: 11px;">
<p>Technical support: <a href="mailto:support@domain.com">support@domain.com</a></p>
</div>
ExtraWidth: 300
ExtraHeight: 180As you can see in the example above, the Login controller hosts a BorderPanel which allows you to integrate other controllers in it, such as an HtmlPanel.
Here is an example of a login view defined inline in Config.yaml (from the HelloKitto example):
Login:
Controller:
Title: Login to "HelloKitto" %APP_VERSION%
BorderPanel:
NorthView:
Controller: HtmlPanel
Height: 80
Html: |
<div style="text-align: center">
<p/>
<p><img src="%IMAGE(hello_kitto_150)%"></img></p>
<p/>
</div>
LabelWidth: 150
ExtraWidth: 350
ExtraHeight: 100
LocalStorage:
Mode: Password
AskUser: True
.Default: False
AutoLogin: FalseTitle Bar
The login dialog always shows a title bar at the top. By default the application title (from Config.yaml → AppTitle) is used. You can override it with the Title property:
Controller: Login
Title: Welcome to My ApplicationThe title bar uses the same dark chrome style as dialog headers (--kx-chrome-dark background).
BorderPanel
The BorderPanel node allows you to embed custom content above and below the login form.
NorthView
The NorthView/Controller sub-node defines a controller rendered above the login form, typically used for a logo or branding:
BorderPanel:
NorthView:
Controller: HtmlPanel
Height: 100
Html: <center><img src="%IMAGE(logo)%"></center>SouthView
The SouthView/Controller sub-node defines a controller rendered below the login form (after the submit button), typically used for support info or disclaimers:
BorderPanel:
SouthView:
Controller: HtmlPanel
Height: 60
Html: |
<div style="text-align: center; font-size: 11px;">
Technical support: +39 0123 456789
</div>Both NorthView and SouthView are optional and can be used independently.
Dialog Sizing
Use ExtraWidth and ExtraHeight to adjust the dialog dimensions:
Controller: Login
ExtraWidth: 300
ExtraHeight: 180These values are added to the base dialog size. You can also set a freeform CSS Style property.
Form Customization
The FormPanel sub-node controls the form fields:
| Property | Default | Description |
|---|---|---|
FormPanel/UserName | User Name | Label for the user name field |
FormPanel/Password | Password | Label for the password field |
FormPanel/Language | Language | Label for the language selector |
FormPanel/LabelWidth | 100 | Width in pixels for field labels |
FormPanel/InputStyle | (empty) | Extra CSS for input fields |
FormPanel/ButtonStyle | (empty) | Extra CSS for the login button |
FormPanel/BodyStyle | (empty) | Extra CSS for the form body |
FormPanel/RememberCredentials | Remember Credentials | Checkbox label when LocalStorage/Mode is Password |
FormPanel/RememberUserName | Remember User Name | Checkbox label when LocalStorage/Mode is UserName |
LocalStorage
The LocalStorage sub-node controls persistent credential storage in the browser's localStorage:
Controller: Login
LocalStorage:
Mode: Password
AskUser: True
.Default: False
AutoLogin: False| Property | Values | Description |
|---|---|---|
Mode | UserName, Password, (empty) | What to store. Password stores both user name and password. UserName stores only the user name. Empty or missing disables storage. |
AskUser | True / False | If True, shows a checkbox letting the user opt in/out of storage. |
AskUser/Default | True / False | Default checked state of the checkbox (default: True). |
AutoLogin | True / False | If True and both fields are pre-filled from localStorage, the form is automatically submitted after a short delay. |
WARNING
The LocalStorageMode shorthand (e.g. LocalStorageMode: Password) is still accepted for backwards compatibility but the LocalStorage sub-node form is preferred as it allows full control.
Links
You can enable clickable links below the credential fields by adding boolean nodes:
Controller: Login
ResetPassword: True
RegisterNewUser: True
PrivacyPolicy: TrueEach link triggers a view request (kx/view/ResetPassword, etc.) so the corresponding views must be defined. You can customize the link style with HrefStyle:
ResetPassword: True
HrefStyle: color: blue; font-size: 11px;Default labels (translatable):
- ResetPassword →
Password forgotten? - RegisterNewUser →
New User? Register... - PrivacyPolicy →
Privacy policy...
Pre-login views must declare ACName: empty
The link targets are routes the user reaches before authenticating, so they must be declared public — otherwise the authentication gate returns 404 + empty body. Add an empty ACName: at the top of each linked view's YAML:
# Views/RegisterNewUser.yaml
ACName: # explicit empty value → public view
Controller: ...TKMetadata.GetACURI returns '' for views with empty ACName:, which TKAccessController.GetAccessGrantValue treats as "always granted" — the auth gate detects this and lets every related route through (the GET that renders the view, the POST that submits the form, any Blob/Upload/Tool used inside it). Same convention applies to any custom landing view that must be reachable pre-login.
HtmlPanel pre-login also needs IsModal: True
Form and TKXFormController descendants are modal by default; everything else (including HtmlPanel) is embedded in a tab. Pre-login views linked from the Login form have no tab system to attach to, so an HtmlPanel-based PrivacyPolicy (or any informational page reached pre-login) must declare IsModal: True explicitly to render as a dialog overlay instead of being appended to the page background.
# Views/PrivacyPolicy.yaml
ACName:
Controller: HtmlPanel
IsModal: True
AllowClose: True
FileName: Privacy.htm
Width: 600
Height: 500The dialog overlay does not add inner padding to the embedded HTML body — if the source .htm is a bare fragment, wrap it in a styled root element (e.g. <div style="padding: 1.25rem 1.75rem; line-height: 1.6;">…</div>) so the text gets sensible margins.
Language Selector
If LanguagePerSession: True is set in Config.yaml, the login form displays a language drop-down that lets the user choose the UI language before logging in. The selected language is stored in the session and used for all subsequent localized strings.
# Config.yaml
LanguagePerSession: TrueEnvironment / database choice
When the application supports multiple databases (typical of business management software with separate "company" or "fiscal year" environments), you can let the user pick which one to log into via a drop-down placed before the user name field.

The model is self-contained: each database is a complete environment (auth + data). The authentication query runs against the chosen database, so the KITTO_USERS table can be different in each environment. The selected database becomes the active one for the entire session, overriding DefaultDatabaseName. With legacy authenticators (Auth: DB | TextFile | custom) the choice is persisted in a kx_db cookie (30 days) so the same environment is pre-selected on the next visit. With Auth: JWT the choice travels in the db claim of the signed token, so no separate kx_db cookie is set; the JWT cookie path is scoped to the AppPath, eliminating cross-app environment leakage. Trade-off under JWT: once the token expires the next login form pre-selects DefaultDatabaseName instead of the last picked environment (the JWT typically lives 1 hour and slides on every active request, so this only matters after extended idle time).
The feature is opt-in: with no Auth/DatabaseChoices node in Config.yaml, the combo is not rendered and the legacy behavior is preserved.
Configuration
Add DatabaseChoices under the Auth node. The value is a comma-separated list of database names defined under Databases:
# Config.yaml
Databases:
FireDAC_MSSQL: FD
DisplayLabel: Database SQL Server # Optional: shown in the combo.
Connection:
DriverID: MSSQL
...
FireDAC_PostgreSQL: FD
DisplayLabel: Database PostgreSQL
Connection:
DriverID: PG
...
FireDAC_Firebird: FD
DisplayLabel: Database Firebird
Connection:
DriverID: FB
...
Auth: TasKitto
DatabaseChoices: FireDAC_MSSQL, FireDAC_PostgreSQL, FireDAC_Firebird
...Each database entry can carry a DisplayLabel sub-node for a friendlier label in the combo; if absent, the raw config name is shown.
Combo label
The combo uses the standard FormPanel label vocabulary. You can override the label text with:
Controller: Login
FormPanel:
Database: Environment # Default: 'Environment'Default selection priority
The pre-selected option is determined in this order:
- Cookie
kx_db(legacy auth, set on the previous successful login, 30-day lifetime) — replaced by thedbclaim of the JWT cookie when the app runs onAuth: JWT. - The currently active
Session.DatabaseName(rare — first visit of the page). DefaultDatabaseNamefromConfig.yaml.
Showing the active environment elsewhere
Two macros are exposed after a successful login:
%Auth:Environment%— the user-friendly label (Databases/<Name>/DisplayLabel), falling back to the raw config name. Use this in the StatusBar or dialog titles so the displayed text matches what the user picked in the combo.%Auth:DatabaseName%— the raw config name (e.g.FireDAC_PostgreSQL). Useful when you need the exact identifier for diagnostic logs or routing decisions.
Example StatusBar:
# Views/Home.yaml
SouthView:
Controller: StatusBar
Text: Environment: %Auth:Environment% - user: %Auth:USER_NAME%Routing under the hood
TKConfig.GetDatabaseName (the single source of truth used by TKConfig.Database, CreateDBConnection, and every other connection-resolution path in the framework) gives priority to TKWebSession.Current.DatabaseName when set, falling back to DatabaseRouter and then DefaultDatabaseName. So a single per-session value redirects every database operation — including the auth query itself, since the session value is applied before Authenticate runs.
Authentication
The Login controller works with Kittox's pluggable authentication system. The authenticator type is configured in Config.yaml:
Auth: DB
IsClearPassword: False
IsPassepartoutEnabled: True
PassepartoutPassword: password
.Defaults:
UserName: administrator
Password: passwordAvailable authenticator types:
| Type | Description |
|---|---|
DB | Database-backed authentication using KITTO_USERS table with MD5 password hashing |
DBCrypt | Like DB but uses BCrypt for password hashing (recommended). Auto-migrates from MD5 on first login |
TextFile | File-based user list |
OSDB | Operating system user authentication |
| (empty) | No authentication required |
See Authentication for full configuration details.
Footer
The login footer (containing the login button and status indicator) has a styled background matching the form toolbar style, with a top border separator. This is automatic and requires no configuration.
The Login controller renders as a centered dialog window. The login form uses HTMX to submit credentials and receive the server response (success redirect or error message) without a full page reload.
