> For the complete documentation index, see [llms.txt](https://docs.kangal.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kangal.dev/organizations-and-access/members-rbac.md).

# Members and RBAC

Kangal combines direct account roles with a tenant permission catalog. Tenant scope is always checked first: a role never grants a regular user access to a different tenant.

## Direct account roles

| Role                                 | Access model                                                                         |
| ------------------------------------ | ------------------------------------------------------------------------------------ |
| `user`                               | Authenticated account without Admin API access.                                      |
| `admin_readonly` / `read_only_admin` | Can read admin endpoints but cannot use `POST`, `PUT`, `PATCH`, or `DELETE`.         |
| `admin`                              | Can read and mutate admin resources in its own tenant.                               |
| `super_admin`                        | Global operator. Can select tenant scope and perform restricted platform operations. |

Admin endpoint authorization first maps the HTTP method to read or write. A read-only admin receives `403` for mutating methods even when the URL is otherwise visible.

Only a super-admin can use `POST /auth/users/{user_id}/role`. Role updates accept `user`, `admin`, and `super_admin`. Invitations and enterprise JIT can also create `admin_readonly` accounts.

## Permission catalog

The tenant permission matrix contains:

| Category      | Permissions                                 |
| ------------- | ------------------------------------------- |
| Gateways      | `gateways:read`, `gateways:write`           |
| Workspaces    | `workspaces:read`, `workspaces:write`       |
| Services      | `services:read`, `services:write`           |
| Routes        | `routes:read`, `routes:write`               |
| Plugins       | `plugins:read`, `plugins:write`             |
| Consumers     | `consumers:read`, `consumers:write`         |
| RBAC          | `rbac:read`, `rbac:write`                   |
| Audit         | `audits:read`                               |
| Observability | `observability:read`, `observability:write` |

The built-in `admin_readonly` and `read_only_admin` roles default to every `:read` permission. `admin` and `super_admin` default to the whole catalog. Tenant-specific matrix overrides can replace the permissions of system roles.

## Authorization requirements

Every Admin API request is constrained by the caller's tenant, direct account role, and HTTP method. Permission-aware endpoints additionally require the named catalog permission. A permission-matrix entry never expands tenant scope or turns a read-only direct role into a write role.

Use tenant separation and direct account roles as the primary authorization boundary. When an endpoint declares a catalog permission, verify both the direct role and that permission with a non-privileged test account before production use.

## Manage members

Open `/<locale>/dashboard/admin/organizations` and select **Users** to inspect tenant accounts. Account creation is available through:

* An organization invitation.
* Enterprise JIT provisioning.
* SCIM user provisioning.
* `POST /auth/register` by an authenticated admin.
* An operator-managed federated OAuth signup policy.

Users are unique by username and email inside a tenant. A regular admin can list and update users only in their tenant. User deletion removes the user record; SCIM deprovisioning instead marks the user inactive and revokes sessions.

## Teams

Teams store a tenant-scoped name, optional RBAC organization ID, member user IDs, role IDs, and metadata. The console's **Teams** section updates these arrays through `/admin/rbac/teams`.

```bash
export KANGAL_URL='https://api.example.com'
export KANGAL_API_TOKEN='<tenant-admin-token>'

curl --request POST "$KANGAL_URL/admin/rbac/teams" \
  --header "Authorization: Bearer $KANGAL_API_TOKEN" \
  --header 'Content-Type: application/json' \
  --data '{
    "tenant_id": "acme",
    "name": "Platform Operators",
    "member_user_ids": ["<user-id>"],
    "role_ids": ["admin_readonly"]
  }'
```

Duplicate member and role IDs are removed. Team names are unique inside the tenant. If `organization_id` is supplied, it must identify an RBAC organization in the same tenant.

### Team authorization behavior

Team role IDs organize governance records. Session authorization uses the member's direct account role, so assign and verify that role separately when team membership changes.

## Manage permission entries

The console edits custom roles one at a time. The API also supports a matrix replacement request for selected roles:

```bash
curl --request PUT "$KANGAL_URL/admin/rbac/permission-matrix" \
  --header "Authorization: Bearer $KANGAL_API_TOKEN" \
  --header 'Content-Type: application/json' \
  --data '{
    "tenant_id": "acme",
    "roles": [
      {"key": "admin_readonly", "permissions": ["routes:read", "observability:read"]}
    ]
  }'
```

Only roles included in the request are changed. RBAC organization, team, role, and matrix mutations are audit logged.

## Troubleshooting

| Symptom                               | Check                                                                                                         |
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `403 Admin write role required`       | A read-only admin attempted a mutating method.                                                                |
| `403 Missing required permission`     | The direct token role lacks the matrix permission used by that endpoint.                                      |
| `403` remains after a matrix change   | Confirm the direct role, tenant, HTTP method, and the permission declared by the endpoint.                    |
| Team membership did not change access | Assign the member's direct account role separately.                                                           |
| A recent role change appears stale    | Refresh or sign in again so the access token carries the new role; revoke old sessions for immediate removal. |
| A foreign record returns `404`        | Tenant-scoped detail endpoints intentionally hide cross-tenant resources.                                     |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.kangal.dev/organizations-and-access/members-rbac.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
