Ucotron Cortex
Guides by flow

White-label

Per-organization branding, with measured contrast and rejected SVGs.

Diagrama: White-labelFlujo de white-label: leer y actualizar el branding de la organización, y cómo se refleja en los artefactos generados.

Alta en WorkOS · MANUAL

Membresía con admin:write

Login

PUT /v1/org/branding

POST /v1/org/branding/logo

Consola brandeada

Diagrama: White-labelFlujo de white-label: leer y actualizar el branding de la organización, y cómo se refleja en los artefactos generados.

Alta en WorkOS · MANUAL

Membresía con admin:write

Login

PUT /v1/org/branding

POST /v1/org/branding/logo

Consola brandeada

Fuente del diagrama (mermaid)
flowchart LR
    W[Alta en WorkOS · MANUAL] --> M[Membresía con admin:write]
    M --> L[Login]
    L --> B[PUT /v1/org/branding]
    B --> G[POST /v1/org/branding/logo]
    G --> C[Consola brandeada]

Organization creation is manual and done by a person. Creating organizations by API means mutating the identity provider: a bug there puts someone in the wrong tenant — legitimately inside, with every later control waving them through — which is the worst class of leak in a multi-tenant product.

bash
curl -sS "$SBOX/v1/org/branding" -X PUT \
  -H "authorization: Bearer $TOKEN" \
  -H "idempotency-key: branding-demo-1" \
  -H "content-type: application/json" \
  -d '{"displayName":"Aseguradora Demo","colors":{"primary":"#7c2d12","accent":"#065f46"}}'

Contrast

Branding that does not reach WCAG AA is rejected with 422, the measured ratio, and a color that does pass. The client uploading their corporate light blue is not choosing badly on purpose: they are choosing without knowing their own team will not be able to read the console.

What gets measured: text over the brand color at 4.5:1 (where the text lives), and brand over background at 3:1 in both themes. A color is not required to pass against both backgrounds, because none does — the brand defines a hue and each theme uses its own step.

512 KiB maximum, image/svg+xml or image/png. An SVG with <script>, an on* handler, javascript:, <foreignObject>, <iframe> or an external entity is rejected, not cleaned: blacklist sanitizing is a race the defender loses, and accepting one would be persistent XSS in the session of the client's entire organization.

What breaks

403 if the credential lacks admin:write. The permission comes from the canonical catalog — there is no org:branding:write, because a permission the catalog does not know is not granted by any role template.

See also the full demo flow.

Endpoints in this guide

On this page