feat(auth): GET /v1/auth/memberships synthetic single-tenant stub #65
No reviewers
Labels
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
psa-systems/bunyip!65
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/auth-memberships-stub"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The mokosh-clients SPA hits
<issuer>/v1/auth/membershipsafter sign-in to populate its tenant switcher and brand label (see mokosh-clients src/hooks/auth.rs:240+). Bunyip returns 404 today because the endpoint was always slated for the phase-04 multi-tenant work (per AUDIT.md and dev-docs/milestone-1-handoff.md, which records the M1 decision: "a paying MSP is modelled as one owner-user account; org-level billing and seats stay deferred to multi-tenant work"). The 404 surfaces in the SPA asmemberships load failed: HTTP 404and an empty brand area; non-fatal but ugly.This PR ships the route with a synthetic single-tenant response derived from the authenticated user, so the SPA can decode something coherent without bunyip having to grow an org/membership domain yet. When the real phase-04 multi-tenant story lands, this handler is replaced by a real-row query against an
org_membershipstable; the wire shape stays.What the endpoint returns:
{
"memberships": [{
"tenant_id": "00000000-0000-0000-0000-000000000001",
"tenant_name": "<user.email>",
"tenant_kind": "personal",
"role": "owner",
"status": "active",
"is_active": true
}],
"active_tenant_id": "00000000-0000-0000-0000-000000000001"
}
The
tenant_idisUuid::from_u128(1)to match mokosh-server's OIDC_DEFAULT_TENANT_ID fallback (auth/middleware.rs::default_bunyip_tenant_id). Every user JIT-provisioned from a bunyip at+jwt lands in that mokosh tenant today, so the SPA seeing the same id here makes itsactive_membership()lookup line up with the data scope its PSA API calls actually run against.tenant_nameis the user's email so the SPA brand area shows something informative.Response body is raw JSON, not wrapped in
ApiResponse, because the SPA decodes the body directly viaissuer_get_authed::<T>(mokosh-clients src/modules/oidc/flow.rs:361). Field names + types are pinned in a unit test against the SPA'sMembershipView+Bodyshapes.Files:
synthesise_memberships_responsehelper +get_membershipshandler + unit test pinning the shape.get_memberships.GET /membershipsunder the existing/v1/auth/*scope.Verified locally:
A pre-existing
config::tests::test_config_defaultsfailure inbunyip-domainreproduces on main withRUST_LOGin env; unrelated.The mokosh-clients SPA hits `<issuer>/v1/auth/memberships` after sign-in to populate its tenant switcher and brand label (see mokosh-clients src/hooks/auth.rs:240+). Bunyip returns 404 today because the endpoint was always slated for the phase-04 multi-tenant work (per AUDIT.md and dev-docs/milestone-1-handoff.md, which records the M1 decision: "a paying MSP is modelled as one owner-user account; org-level billing and seats stay deferred to multi-tenant work"). The 404 surfaces in the SPA as `memberships load failed: HTTP 404` and an empty brand area; non-fatal but ugly. This PR ships the route with a synthetic single-tenant response derived from the authenticated user, so the SPA can decode something coherent without bunyip having to grow an org/membership domain yet. When the real phase-04 multi-tenant story lands, this handler is replaced by a real-row query against an `org_memberships` table; the wire shape stays. What the endpoint returns: { "memberships": [{ "tenant_id": "00000000-0000-0000-0000-000000000001", "tenant_name": "<user.email>", "tenant_kind": "personal", "role": "owner", "status": "active", "is_active": true }], "active_tenant_id": "00000000-0000-0000-0000-000000000001" } The `tenant_id` is `Uuid::from_u128(1)` to match mokosh-server's OIDC_DEFAULT_TENANT_ID fallback (`auth/middleware.rs::default_bunyip_tenant_id`). Every user JIT-provisioned from a bunyip at+jwt lands in that mokosh tenant today, so the SPA seeing the same id here makes its `active_membership()` lookup line up with the data scope its PSA API calls actually run against. `tenant_name` is the user's email so the SPA brand area shows something informative. Response body is raw JSON, not wrapped in `ApiResponse`, because the SPA decodes the body directly via `issuer_get_authed::<T>` (mokosh-clients src/modules/oidc/flow.rs:361). Field names + types are pinned in a unit test against the SPA's `MembershipView` + `Body` shapes. Files: - bunyip-api/src/handlers/auth.rs: new `synthesise_memberships_response` helper + `get_memberships` handler + unit test pinning the shape. - bunyip-api/src/handlers/mod.rs: re-export `get_memberships`. - bunyip-api/src/routes/auth.rs: register `GET /memberships` under the existing `/v1/auth/*` scope. Verified locally: - SQLX_OFFLINE=true cargo check --tests - SQLX_OFFLINE=true cargo clippy --tests -- -Dwarnings - cargo fmt --all --check - cargo test synthesise_memberships_response_matches_spa_shape (1/1 passing) A pre-existing `config::tests::test_config_defaults` failure in `bunyip-domain` reproduces on main with `RUST_LOG` in env; unrelated.