fix(keycloak): org create must send a domain (KC 26 rejects domainless)
Onboarding provisioning failed at CreateOrgAndInvite with create org: 400 "You must provide at least one domain" — Keycloak 26 requires every organization to carry at least one domain, and the payload sent none. Membership is registry-authoritative (model B2), so we do not use Keycloak email-domain auto-join; a synthetic per-tenant domain <slug>.tenant.breakpilot.com satisfies the constraint, is unique (slug is unique in the registry), and never clashes with a real deliverable mail domain. Discovered live: with the service account now holding manage-realm the 403 is gone and this is the next real blocker to onboarding every customer's org on KC 26. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CNdLL9BdsWm7MCyui5ffPD
This commit is contained in:
co-authored by
Claude Fable 5
parent
84516e9b4f
commit
67264d57ed
@@ -13,6 +13,11 @@ import (
|
||||
|
||||
// ─── organizations API ───────────────────────────────────────────────────
|
||||
|
||||
// orgDomainSuffix namespaces the synthetic org domain. The slug is unique in
|
||||
// the registry, so "<slug>.tenant.breakpilot.com" is unique per organization
|
||||
// and never a real deliverable mail domain we might clash with.
|
||||
const orgDomainSuffix = ".tenant.breakpilot.com"
|
||||
|
||||
type orgCreate struct {
|
||||
Name string `json:"name"`
|
||||
Alias string `json:"alias"`
|
||||
@@ -50,6 +55,16 @@ func (a *HTTPAdapter) CreateOrgAndInvite(ctx context.Context, in InviteInput) (*
|
||||
Name: in.Name,
|
||||
Alias: in.Slug,
|
||||
Description: fmt.Sprintf("Auto-provisioned from tenant-registry %s", in.TenantID),
|
||||
// Keycloak 26 rejects an organization with no domain ("You must
|
||||
// provide at least one domain"). Membership is registry-authoritative
|
||||
// (model B2), so we do NOT use Keycloak's email-domain auto-join; a
|
||||
// synthetic per-tenant domain derived from the unique slug satisfies
|
||||
// the constraint without depending on the customer's real mail domain
|
||||
// (which may be a shared public domain and would collide across
|
||||
// tenants). Unverified is fine — verification only gates auto-join.
|
||||
Domains: []map[string]any{
|
||||
{"name": in.Slug + orgDomainSuffix, "verified": false},
|
||||
},
|
||||
Attributes: map[string][]string{
|
||||
"tenant_id": {in.TenantID},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user