Branding and sign-in methods
Give the sign-in page your tenant's name, brand color and self-hosted logo, and choose which sign-in methods it offers.
Each tenant brands its own sign-in experience: organization name, brand color and logo, plus the sign-in methods the page offers. Branding is edited in the console (Organization settings, with a live preview of the sign-in page) or over the API with the tenant:manage permission. It applies on accounts.obexal.com and, identically, on your custom domain.
Name and brand color
The tenant name and the branding blob are updated with PATCH /v1/admin/tenant. The brand color lives under the branding.primary key (a hex code) and tints the buttons and accents of the sign-in page:
curl -X PATCH https://accounts.obexal.com/v1/admin/tenant \
-H "Authorization: Bearer $OBX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Acme SAS","branding":{"primary":"#0e7490"}}'
# 200 {"tenant":{"id":"...","name":"Acme SAS","slug":"acme","branding":{"primary":"#0e7490"},...}}The console shows a live preview of the sign-in page as you edit the color, before you save.
The logo, self-hosted
The logo is uploaded directly to the platform (self-hosted object storage, no third-party CDN in the sign-in path). Send the raw image bytes:
curl -X PUT https://accounts.obexal.com/v1/admin/tenant/logo \
-H "Authorization: Bearer $OBX_TOKEN" \
--data-binary @logo.png
# 200 {"tenant":{...,"branding":{...,"logoUrl":"https://accounts.obexal.com/v1/tenants/acme/logo?v=..."},...}}The constraints are strict, and deliberate:
| Rule | Why |
|---|---|
| PNG, JPEG or WebP only | Format is detected from the bytes, never from your Content-Type header |
| 512 KB maximum | Larger uploads are rejected with 413 |
| 2000 px maximum per side (PNG/JPEG) | Guards against decompression bombs |
| SVG refused | An SVG can embed script: an XSS surface when served from the platform origin |
| One file per tenant | Uploading again replaces the previous logo in place |
On success, branding.logoUrl is set to a versioned URL (?v=<etag>), so browser and proxy caches pick up a new logo immediately. The logo is served publicly at GET /v1/tenants/{slug}/logo with long-lived caching. DELETE /v1/admin/tenant/logo removes the file and clears branding.logoUrl.
If you need a vector logo, host the SVG on your own domain and reference it from your site; the sign-in page logo itself is raster only.
Sign-in methods per tenant
Two flags in the branding blob control what the sign-in page offers. Both are off by default:
| Key | Effect when true |
|---|---|
branding.allowSelfSignup | Shows the account creation link; otherwise the directory is invitation only |
branding.allowPasswordless | Shows the passwordless sign-in option (email code or magic link) |
curl -X PATCH https://accounts.obexal.com/v1/admin/tenant \
-H "Authorization: Bearer $OBX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"branding":{"primary":"#0e7490","allowPasswordless":true}}'What is published, and what stays fixed
The sign-in page reads your branding from a public endpoint, by slug or by verified custom domain:
curl https://accounts.obexal.com/v1/tenants/acme/branding
# {"name":"Acme SAS","slug":"acme","branding":{"primary":"#0e7490","logoUrl":"..."},
# "allowSignup":false,"allowPasswordless":true}Two honest boundaries:
- Output allowlist: only known theming keys (
primary,primaryHover,primaryFg,bg,surface,fg,muted,border,danger,radius,logoUrl) are published. Anything else you store in the branding blob stays private. - Security colors stay fixed: the brand color tints buttons and accents, but the semantic colors of security states (success and warning indicators) are set by the platform and cannot be rebranded. A warning must look like a warning on every tenant.