go-auth
Routes

Org authorization

Organization-local permission, role, grant, invitation and access APIs.

Org authorization

See the org permissions client guide for typed wrappers and React examples of these operations.

WithOrgPermissions(OrgPermissionsConfig{Enable:true}) exposes self access. EnableManagementHTTP:true additionally mounts initialization and management. Organizations must be enabled. All routes authenticate the current session and use rate limiting; writes also use the configured CSRF token and origin checks. Actors come from the session, never the JSON body.

For management paths below, BASE is /auth/orgs/{orgID}/authorization. The exact operation keys listed below start with goauth.org..

Method and pathAccessInput / result
GET /auth/orgs/{orgID}/accessCurrent enabled member role{role,isFullAccess,permissionKeys,assignmentRevision,revision}
POST BASE/initializeCurrent ownerNo body; 204
GET BASE/library-permissionsProtected owner{permissions:[{key,name,description}]}
PATCH BASE/library-permissionsProtected owner{create:[keys],delete:[keys]}; atomic result {created,deleted,unchanged}
GET BASE/permissionspermissions.readlimit, offset; {permissions:[...]}
POST BASE/permissionspermissions.create{key,name,description?}; definition, 201
PATCH BASE/permissions/{permissionID}permissions.updateIf-Match header; {name?,description?,isEnabled?}; business definition only
DELETE BASE/permissions/{permissionID}permissions.deleteRequired If-Match header; 204
GET BASE/rolesroles.readlimit, offset; {roles:[...]}
POST BASE/rolesroles.create{slug,name,description?,permissionKeys?}; role, 201
PATCH BASE/roles/{roleID}roles.updateIf-Match header; {name?,description?,isEnabled?}
PUT BASE/roles/{roleID}/permissionsroles.updateIf-Match header; {permissionKeys:[...]}; replaces grants, [] clears
DELETE BASE/roles/{roleID}roles.deleteRequired If-Match header; 204
GET BASE/members/{userID}/roleroles.read, including for self{role,assignmentRevision}
GET BASE/members/{userID}/accessroles.read for another memberTarget member's effective access
PUT BASE/members/{userID}/roleroles.assign{roleId,expectedRoleRevision,expectedAssignmentRevision}; assignment

Guarded permission/role PATCH, grant-replacement PUT and DELETE requests all require one strong revision tag in If-Match, for example If-Match: "3", from that resource's revision. Do not send expectedRevision in JSON or the query string; these former transports are rejected. Missing/malformed headers return 400 invalid_input; weak tags, wildcards and tag lists are unsupported. Stale preconditions return 412 with the existing authorization conflict code. Other business conflicts still return 409. Role assignment retains the two JSON fields expectedRoleRevision and expectedAssignmentRevision, because it checks two separate records. Direct Go service inputs retain ExpectedRevision.

Other successful reads/updates return 200. Authorization IDs are lowercase, hyphenated UUIDs. Management JSON is limited to 64 KiB and rejects unknown fields and trailing documents. Lists default to 20; limits 1–100 are accepted, zero selects the default, and offsets must be nonnegative. Role/definition results include orgId, IDs, metadata, enabled state, revisions and timestamps. Built-in roles expose systemKey; custom roles contain explicit permissionKeys. The member-role GET remains available to an authorized caller when the target is banned or its assigned role is disabled; it returns the assignment revision needed to replace that role. Authorized target-access reads return that metadata with an empty effective permissionKeys array and isFullAccess: false for disabled roles or banned members. The requesting caller must still pass authentication and authorization.

The top-level access revision tracks guarded authorization management, not all membership or account/session changes. Self-leave, invitation acceptance and platform-admin member overrides do not advance it. It must not be used as an access-cache or complete change cursor; see the revision contract.

Business-definition deletion enforces the same held-key delegation bound as updates, and still rejects referenced definitions. In the current grant model, owners can delete unused business definitions; non-owners cannot bypass either check.

With the feature enabled, existing org operations use these exact permission checks in addition to membership and business invariants:

OperationPermission
Read orggoauth.org.organization.read
Update orggoauth.org.organization.update
Delete orggoauth.org.organization.delete
List/count membersgoauth.org.members.read
Direct AddMembergoauth.org.members.create
Remove another membergoauth.org.members.remove; touching an owner also requires protected owner identity
Update fixed member rolegoauth.org.roles.assign; old/new delegation bounds and owner restrictions apply
Create/read/resend/delete org invitationsgoauth.org.invites.create/read/resend/delete, respectively

Invitation creation accepts either {email,role} or {email,orgRoleId,expectedRoleRevision}. The latter also requires roles.assign. Malformed or noncanonical orgRoleId values return 400 invalid_input. Membership responses expose orgRoleId and, after explicit assignment, orgRoleAssignmentRevision; their fixed role remains the owner/admin/member classification used by legacy APIs and ownership counters. Invitation responses expose orgRoleId and orgRoleRevision for the proposed role.

The same authorization, delegation and revision checks run in direct Go services. Use GET /auth/orgs/{orgID}/access for self-inspection without roles.read. Resending a role-linked invitation requires the resender's invites.resend grant and the original inviter's current delegation authority; even an owner must delete and recreate an invitation after that authority is lost. An invitation whose saved role changed or is disabled returns 409 org_invite_role_changed on acceptance or resend. An authorized inviter must delete and recreate it after reviewing the current role. See the usage guide for initialization, invitation invalidation and the boundary between app and org administration.

On this page