Skip to content

First-class service-principal path for API integrations (5 hand-assembled pieces today) #322

Description

@modernitconsultants

Design ask, following #317 and #321: a first-class service principal story for server-to-server integrations.

What an integrator currently has to assemble by hand (all measured, all working — but every piece was archaeology):

  1. A Keycloak client with service accounts enabled + an audience mapper (passport requires aud to contain the primary client).
  2. azp acceptance — impossible until feat(auth): KEYCLOAK_ALLOWED_AZP — let additional realm clients call the API #317; the guard hard-requires the browser client's identity.
  3. A property_ids claim via a hardcoded-claim mapper, because PropertyScopeGuard admits by claim (or platform-admin role) — this is genuinely nice design, but undocumented for the service-account case.
  4. Realm roles per controller (reservations, revenue_manager, …) — fine.
  5. A local users row for any @RequirePermissions route: PermissionsGuard.findLocalUser resolves by keycloak_sub then email, and a service account has no email — so integrators must insert a row (keycloak_sub = the service account's user id) plus a local role with permission keys. There's no API for this; we did it with operator SQL.

Suggestion: either a documented "integration principal" setup path (docs + maybe a CLI/seed helper that creates client-with-mappers + users row + a narrow local role in one step), or a service-principal concept that bypasses the local-user resolution for token types that can't have one. Also worth considering: a narrower built-in role for room/room-type management — today the room controllers require general_manager/admin, so any tooling that manages inventory needs one of the two broadest roles in the realm.

One error message earned praise from our infra reviewer along the way: "No local user account is linked to this login" names its guard exactly — worth preserving through any refactor.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions