Repository navigation
feat(organizations): carry organization roles and permissions in the access token - #577
Merged
Merged
Conversation
…access token Adds org_roles and org_permissions beside org_id for the active organization, and a catalogue of organization roles seeded from what memberships already hold. Assigning a role outside the catalogue answers 400. Role changes need step-up and are audited. Only an owner or an instance admin:write can grant or remove owner, and other managers can only grant a role whose permissions they hold, so an organization admin can no longer make themselves owner. Fixes removal from an organization not reaching the token: refresh copied org_id from the session until it ended. The mint now reads the membership. Closes #416.
Bccorb
force-pushed
the
feat/organization-roles-in-token
branch
from
November 6, 2026 06:04
d503ea3 to
2978157
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #416. Stacked on the #415 branch, so this diff shows only the organization work. Merge that first; this then retargets to
main. Design indocs/adr/0004-permissions-and-organization-roles.md.What
org_rolesandorg_permissionsbesideorg_id, for the active organization only. Organization roles never appear inroles, so a guard onadmindoes not pass for an organization admin. Absent with no active organization, and on recovery tokens.organization_rolescatalogue, managed at/admin/organization-roles, withPUT /admin/roles/organization/:roleName/permissionsfor mappings. The migration seeds the built-inowner,adminandmemberand every value memberships already hold, spelled as they are, and rewrites no membership. Built-ins and roles still held cannot be deleted.GET /users/meandGET /users/me/permissionsreport the same organization data, checked against the membership on each call.org_rolescounts against the 1 KiB budget, andpermissions_omittedreplaces all three arrays. 50 long role names could overflow the cookie by themselves.docs/admin-operations.mdanddocs/api-contract.md.Security fixes, each reproduced on the code before the fix
org_idfrom the session, so a removed member kept it until the session ended, and with this PR would have kept the roles and permissions too. The mint now reads the membership, drops the claims and clears the session's organization. The test failed with the organization id where it expected null.owner. The member PATCH had no step-up and no audit. The test got 200 where it expected 403. Now only an owner or an instanceadmin:writecan grant or removeowner, or remove an owner from the organization, and any other manager can only grant a role whose permissions they hold.Behavior changes for the release notes
PATCH /organizations/:id/members/:userIdneeds step-up, including for a change toscopesalone.organization_member_added,organization_member_updatedandorganization_member_removed, and a refusal asorganization_member_role_grant_refused.For review
tests/postgres/sessionExchange.spec.tsnow step up first, because they assumed the member PATCH had no step-up. The device-session gate they test is unchanged.GET /admin/rolesis admin-only. Left out as not yet needed.scopesstay out of the token. Provider tokens are not covered here; seamless-auth-oidc-provider#47 takes that up in Wave 4.Testing
Run locally on this branch with
@seamless-auth/types0.38.0:postgres:18-alpine: 3,264 passed, 1 todo. The Postgres spec runs the migration against a legacy membership and mints a real token before and after removalNot run: the conformance harness. Adapter guards arrive with step 3 of Wave 3, and they wait on review of this claim shape.
Release
Part of the held API v0.23.0 release. #566 stays open. Minor changeset included. New migration:
20261105130000-add-organization-roles.