Customize the sign-in page
Name your app on the hosted sign-in page, and set its logo, colours, layout, links, words in every language, and stylesheet, per org or per app.
The hosted sign-in page is the first screen of your product a new customer sees, and it should say whose it is. Everything on it is set under User Management → Access → Authentication → Sign-in page, with a preview beside the settings that follows every change before you save. Your app's code changes for none of it, beyond one optional line for the language.
Step by step, with screenshots: Customize the sign-in page.
Whose page it is
The page names your app, in its heading ("Sign in to Acme"), in the browser tab ("Sign in to Acme", or "Forgot your password? · Acme" where the title does not name it) and as the logo's text for screen readers. It never says BuildBase, except in the small "Secured by" badge, which a plan with white-label can hide.
| Setting | Where it shows |
|---|---|
| Name | The {app} in screen titles, people's authenticator apps, the heading of their backup codes, the wallet message, and {{appName}} in emails |
| Small name | The browser tab. Empty uses Name |
| Logo | Above the title. A second logo for dark mode is optional. Emails can show it with {{logoUrl}} |
| Favicon | The browser tab's icon. Empty uses the logo |
| Website | Where the logo links |
With no Name set, the page uses your organization's name. With neither, it names no app at all ("Sign in"), rather than ours. Emails follow the same Name unless you set the App Name merge tag yourself, under Email → Merge tags; Templates and merge tags has the details. The page an emailed sign-in link opens carries your branding too, even in a browser other than the one that asked for the link.
One org, several apps. Each client can have its own display name, logo, dark logo, favicon and brand colour, in the client's Sign-in page section (open the client on the Settings tab). A sign-in started by that client's app shows them, and so do the consent and device screens that name the app. So do the emails that sign-in sends (the code or link, the welcome, the sign-in notices): they name that app and carry its logo. Anything left empty falls back to the org's settings. The client's console title is a label for you and is not shown to the people signing in, except for an agent that registered itself, whose own name is all there is.
Words on the page
Every sentence on the page that you can write is in one place, Words on the page: each screen's title and the line under it, the waitlist's two screens, the sign-up consent checkbox, and the split screen panel's headline and line. Ours name your app and are already in every language the page speaks, so most apps never change them. Buttons, field labels and errors are always ours, in every language.
Write {app} where the app's name belongs: Sign in to {app} reads "Sign in to Acme Analytics" for that client and "Sign in to Acme" for the others. A box left empty shows ours, greyed in the box; clearing a box is how you go back to ours.
For one app. Pick an app beside Editing to give it its own words, for when its sign-in is for different people or a different job, such as a staff app beside a customer app. A box you leave empty keeps the organization's. The app's words are saved with its client, by the same Save. The client's own Sign-in page section says whether it has words of its own and links here.
In another language. Pick a language beside in to write your words in it. Each box shows the default-language sentence above it, and Start from the English copies it in to edit. Our words are already translated, so write a language only where you changed ours. Nothing is machine translated: every sentence in another language is one you wrote.
Which sentence a visitor reads. For a visitor signing in to an app and reading a language, each sentence is the first of: the app's words in that language; the app's words; the organization's words in that language; the organization's words; ours, in that language. An app's own words come first even over the organization's translation, and the editor warns when that leaves a language reading English.
A language with no version of your words. One setting decides what its visitors read: your words as written (the default, so no page changes until you choose), or ours in their language, so the whole page speaks theirs. The editor shows what a visitor would read under each before you pick.
Out of date. A translation remembers the sentence it was written from. When that sentence changes, the translation is marked May be out of date, with the old and new side by side, until you edit it or choose Mark as checked. The page keeps showing it meanwhile.
Where your words show is a table of every sentence in every language, and what each one reads: yours, ours, the organization's, not translated, or may be out of date. Choose a cell to edit that sentence.
The waitlist's words show only while sign-up is in waitlist mode, and the consent wording only on the sign-up page of an app whose consent checkbox is on; the editor says when nobody sees them.
Brand
| Field | What it sets |
|---|---|
| Brand colour | Buttons, links and focus rings, as #RRGGBB. Button text is black or white, whichever reads better on it |
| Page background | The page behind the sign-in card, as #RRGGBB. Empty follows the light or dark theme |
| Background image | An image behind the card: filling the page, or repeated as a pattern for a small tile |
| Corners | Square, slightly rounded, rounded or very rounded: the card, fields and buttons |
| Light or dark | Follow the device, always light, or always dark |
| Font | Inter (the page's own), the device's own font, a named Google font, or a font file of your own |
Leave a field empty to keep the page's own look for it. Changes show the next time a sign-in page is opened.
Contrast. Buttons use your brand colour exactly as you set it. Links, focus rings and other text drawn in it use a shade of it that is readable on each theme: a navy brand is lightened for dark mode, a yellow one darkened for light mode. The settings warn when the colour itself reads poorly, and the preview shows both themes. With no brand colour the page uses a neutral one, near black in light mode and near white in dark.
Fonts. The named fonts are Roboto, Open Sans, Lato, Montserrat, Poppins, Nunito, Work Sans, DM Sans, IBM Plex Sans, Source Sans 3, Merriweather and Lora. They load from Google Fonts on the sign-in page, so the visitor's browser fetches them from Google. A font of your own is a name and an https link to a .woff2 file, and the server holding the file has to let the sign-in page fetch it.
Layout
| Setting | Choices | Default |
|---|---|---|
| Card position | Centre, left or right of the page, on screens wider than a phone | Centre |
| Card style | Shadow, border, or neither | Shadow |
| Logo | Centred, at the start, or hidden | Centred |
| Logo size | Small (32px), medium (48px) or large (80px) | Large |
| Social buttons | Above or below the email form | Below |
| Social style | A button per provider with its name, or a row of icons | Buttons |
| Header | Centred or aligned to the start | Centred |
A row of icons keeps each provider's name for screen readers.
Split screen. Under Page layout, choose Split screen to put your background image in a panel beside the card: on the left or the right (it mirrors in right-to-left languages), from 1024px wide, with the card centred in the other half. Without a background image the panel is your brand colour. On a phone or a narrow tablet the panel is hidden, or shown as a banner above the card if you prefer. Card position does not apply in a split.
The panel can carry a headline (up to 80 characters) and a line under it (up to 240), such as your product's promise or a customer quote, written under Words on the page like the rest of your words, with a version in each language if you like. They are plain text, at the bottom of the panel over a dark fade so they read on any image. Markup is not accepted: a sign-in page that draws an owner's HTML can be made to look like any other sign-in page.
Links
Help or support, Terms of service and Privacy policy show at the foot of every screen when set, and sign-up names the terms and policy you set. The help link can be a web page or an email address (mailto:[email protected]), and it is also where "lost your authenticator?" and "your account is blocked" point people. Empty hides a link. The people signing in are your users, so our own terms and privacy policy are never shown to them.
Custom CSS
A plan with white-label can add its own stylesheet, under Advanced. It is plain CSS, at most 20,000 characters, and it cannot make the browser fetch anything: the sign-in page holds a password, and a stylesheet that can load a URL can report what a selector matched. So these are refused when you save:
url(),image(),image-set(),cross-fade(),element()andsrc()@import,@font-faceand@namespace- backslash escapes, which can spell any of the above, and
<
Images and fonts have their own settings above. Target these class names, which are kept stable from release to release; the page's generated class names change and are not a contract.
| Class | What it is |
|---|---|
bb-page | The whole page behind the card |
bb-panel | A split screen's image panel and its words |
bb-panel-title | The panel's headline |
bb-panel-text | The line under the panel's headline |
bb-card | The card that holds every screen |
bb-header | The logo, title and description |
bb-logo | The logo image |
bb-title | The screen title |
bb-description | The line under the title |
bb-alert | An error or notice above the form |
bb-content | The form area |
bb-social | The row of social sign-in buttons |
bb-social-button | One social sign-in button |
bb-footer | The bottom of the card |
bb-links | The help, terms and privacy links |
bb-badge | The "Secured by" badge |
bb-language | The language picker |
The page element also carries data-bb-screen with the screen's name, so a rule can apply to one screen: login, register, verify-email, forgot-password, reset-password, check-email, verify-magic-link, email-code, phone-code, phone-signup, wallet-signup, mfa, mfa-setup, trust-device, passkey-enroll, consent, device, device-confirm, beta, error and signout. In a split screen it also carries data-bb-split (start or end) and data-bb-split-phone (hidden or banner), and the card sits inside a main element beside the panel, so write .bb-page .bb-card rather than .bb-page > .bb-card.
[data-bb-screen='register'] .bb-card {
border: 2px solid hsl(var(--primary));
}
.bb-title {
letter-spacing: -0.02em;
}The preview in the console does not apply your stylesheet; open the live page to see it.
What the page tells browsers and search engines
Sign-in pages are not for search results, so every one is sent with noindex, nofollow, as a meta tag and an X-Robots-Tag header. The tab title is the screen's title and your small name (just the title when it already names the app), the icon is your favicon or logo (a neutral padlock when you have neither), and the mobile browser's bar takes the page's background colour. Link previews in chat apps show a plain "Sign in", because they do not run the page's scripts.
The settings are fields on the auth config:
{
"name": "Acme",
"smallName": "Acme",
"supportUrl": "https://acme.com/help",
"branding": {
"primaryColor": "#2563EB",
"backgroundColor": "#F8FAFC",
"radius": "medium",
"colorScheme": "system",
"font": { "family": "Poppins" },
"layout": { "cardPosition": "start", "socialStyle": "icons" }
}
}radius is none, small, medium or large, and colorScheme is system, light or dark. font.family is a name from the list above, inter, system, or custom with name and url. The layout keys are cardPosition (center, start, end), cardStyle (elevated, bordered, flat), logoPosition (center, start, hidden), logoSize (small, medium, large), socialPlacement (top, bottom), socialStyle (buttons, icons), headerAlign (center, start), split (none, start, end) and splitOnPhone (hidden, banner); beside them, branding.backgroundFit is cover or pattern, and branding.panel holds title and text. Every field is optional.
Language
The sign-in pages speak 8 languages, the same ones as the SDK: en, es, fr, de, ja, zh, hi, ar. Arabic is laid out right to left. The page picks the first of these that names a language it speaks:
- Your app's language. The SDK sends it when
signIn()starts the sign-in:auth.localeon the provider, or else the provider's ownlocale. A regional tag is narrowed, soes-MXopens the Spanish page. - The visitor's choice from the language switcher in the page's footer, kept for that tab.
- Their browser's languages, in their order.
- Your default language, from the Language card. It is
defaultLocaleon the auth config. - English.
// In your SaaSOSProvider auth config
auth={{
clientId: 'your-client-id',
redirectUrl: '/callback',
locale: 'fr', // the sign-in page in French, whatever the SDK's own locale
callbacks,
}}Without auth.locale, the provider's locale prop is used, so an app already set to Spanish gets a Spanish sign-in page with no change. An SDK version without auth.locale (0.0.89 and earlier) sends no language, and the page goes by the visitor's choice and their browser. Starting sign-ins without the provider, pass locale to AuthApi.requestAuth(), which sends it in the body of POST /api/v1/auth/request; the page then opens with ?lang= set.
Your own words, in each language. Words you wrote show in a language you gave them a version in, and otherwise as you wrote them, or as ours in that language if you chose that under Words on the page. Words still on ours are translated. A refusal from the server is shown in the page's language when the page knows its reason, and as the server sent it otherwise.
Emails are in English. Codes, magic links and every other email go out in English whatever language the page showed.
Next steps
- Internationalization - the SDK's own screens in the same languages.
- Sign In & Sign Out -
signIn()and the provider's auth config. - Theming - your colours on the SDK's screens inside your app.