The pages the gateway serves
Everything a person has to be shown before they reach your application is served by the gateway itself: no library in your app, no page to write, no template to deploy. They are compiled into the binary, they carry your colours and your logo, and they speak twenty languages.
They are also all Cache-Control: no-store: a page that names a person must never sit in a shared cache.
The pages
| Path | What it is |
|---|---|
/login |
the sign-in page: the credential form, one button per identity provider, the passkey button, and the links to sign up or recover a password when those are open |
POST /logout |
ends this session and comes back to the sign-in page |
GET /logout |
the sign-out an application's own button sends to: from a page of the site it ends the session at once, like the POST; from anywhere else it asks first, with a Sign out button |
/totp |
the second-factor challenge, with trust this browser and the code-by-e-mail link when they are available |
/totp-enroll |
forced enrolment, when a second factor is required and the account has none |
/update-password |
the forced change: a temporary or expired password |
/forgot-password, /reset-password |
recovery by e-mail, and the page the link lands on |
/register, /confirm |
self-registration and address confirmation |
/confirm-email |
the link confirming a new address changed from the profile |
/select-tenant |
which organisation this session works in |
/select-group |
which group, in exclusive-group mode |
/account-pending |
the waiting room: an account that exists and has been granted nothing yet |
/refused |
signed in, and turned away. It names the rule that refused and offers what this session can open |
/profile/... |
the person's own pages: identity, password, second factor, passkeys, authorities, sign-in history, active sessions, API tokens, leaving an organisation |
The unavailability page has no path of its own: it answers any path with 503 while maintenance is on, names the reason from a closed list, and gives an administrator a way through.
The console's sign-in page is the same machinery on the admin port, with one difference: it is always English and always dark. The console is Meerkat's own door and does not take the integrator's settings.
Colours
Application > Built-in pages > Theme. Ten colours, edited as hex values: accent and its text, the surfaces (page, card, field), the text and its muted variant, the outline, and the error colour. They are emitted as CSS variables - --mk-primary, --mk-surface, --mk-on-surface... - once per page, with the light and the dark value side by side, so the visitor's scheme picks the palette with no flash and no script.
Several themes can coexist; exactly one is active. Duplicate one, edit it, preview it, activate it, roll back. Eight presets ship, all on the same base with a different accent: Sentinel's Watch, the default, then Midnight, Lavender, Orchid, Rose, Crimson, Ember and Forest. A Glow checkbox turns the effects and the gradient off in one gesture for a flatter look.
Only hex colours are accepted. Nothing else reaches the page's style block.
Light and dark
The visitor's choice is a three-state button on the page - follow the system, light, dark - stored in the MEERKAT_SCHEME cookie for a year and on the account, so a browser that has never seen this person still gets their scheme after they sign in.
To take the choice away, untick a scheme above its colour column in the theme editor: the remaining one is imposed and the button disappears.
Layout and branding
Layout picks the arrangement: centered, the card in the middle of the page; split, a picture over a full-height half; drawer, an opaque panel against one edge of a full-frame picture; banner, a brand band across the top; bare, the fields on the picture with no card. For split and drawer you also choose a side.
Branding carries the application name and tagline, the logo (uploaded, drawn at normal, large or extra-large size), a browser-tab icon - which follows the logo when you leave it empty - and a page background image with its framing (cover, contain or tile), a dimming veil, and a separate picture for dark mode if you want one.
A page displayed inside somebody's iframe drops the brand and fills the frame by itself. That is decided in the browser, so the HTML served is the same for everyone.
Languages
Twenty catalogues are built in: Arabic, German, English, Spanish, French, Hebrew, Hindi, Indonesian, Italian, Japanese, Korean, Dutch, Polish, Portuguese, Russian, Thai, Turkish, Ukrainian, Vietnamese and Simplified Chinese. English is the reference: a key missing from another catalogue falls back to the English sentence rather than showing blank.
Which of them are offered is DERIVED, never declared: it is the union of what your routes say they speak (Routes > a route > Locales), intersected with what is built in. It never ends up empty - English is the floor. Deploy a route written in Polish and this page offers Polish; retire it and the offer shrinks with it.
For one request, the language is picked in this order:
- the
MEERKAT_LANGcookie, if it names a language you offer; Accept-Language, matched on the language tag;- English when a route speaks it, otherwise the first language offered.
Someone's own choice is written to their account and put back into the cookie when they sign in, so their language follows them to a new browser. Arabic and Hebrew are rendered right to left.
What you cannot change
Your own HTML. The pages are templates inside the binary; the seams are the theme, the layout, the branding and the language catalogues. There is no template-override setting and no file the gateway reads at startup. If you need a sign-in page that is entirely yours, the honest answer today is that Meerkat does not do that yet.