RBAC
IdentSphere's role-based access control is a matrix: roles → permissions.
Permissions are checked at the endpoint via authorize(&auth, &Permission).
The matrix
RbacConfig::default_matrix() ships with five roles and ~25 permissions.
A simplified excerpt:
| Permission | owner | admin | billing | member | viewer |
|---|---|---|---|---|---|
org.read | yes | yes | yes | yes | yes |
org.update | yes | yes | — | — | — |
members.list | yes | yes | yes | yes | — |
members.invite | yes | yes | — | — | — |
members.remove | yes | yes | — | — | — |
billing.read | yes | yes | yes | — | — |
billing.update | yes | yes | yes | — | — |
The full table lives in identsphere_core::rbac::RbacConfig.
Customizing the matrix
Three options:
1. Edit the default
use identsphere_core::rbac::{RbacConfig, Permission, Role};
let mut rbac = RbacConfig::default_matrix();
rbac.grant(Role::Member, Permission::MembersInvite);
rbac.revoke(Role::Admin, Permission::BillingUpdate);
let authorizer = Authorizer::new(db.clone(), Arc::new(rbac));
2. Build from scratch
let rbac = RbacConfig::empty()
.with_role("admin", &[Permission::OrgRead, Permission::MembersInvite])
.with_role("member", &[Permission::OrgRead]);
3. Use host-app permissions
Add new permissions for your own resources. The matrix is generic over any
String permission key:
rbac.grant("admin", "projects.create");
rbac.grant("member", "projects.read");
In your handler:
state
.authorizer
.authorize_str(&auth, "projects.create")
.await
.map_err(RouteError::from)?;
Checking permissions client-side
The capabilities field on every login / session response includes the
caller's full permission set. @identsphere/react exposes it via useCapabilities():
import { useCapabilities } from '@identsphere/react';
function InviteButton() {
const caps = useCapabilities();
if (!caps?.permissions.includes('members.invite')) return null;
return <button>Invite member</button>;
}
This is a UX hint, not authoritative. The server still enforces every permission on the actual request.
Resource scoping
IdentSphere checks auth.organization_id == path.org_id via require_org_match
on every /v1/orgs/:org_id/* route. Cross-org access is 403 BEFORE the
permission check runs.
Platform admins
A separate tier of "platform admin" users (super-admin / support-tier
access) is supported via the optional platform_admins table. These users
get is_platform_admin: true in AuthUser and the capability bundle is
broadened accordingly.
Platform admins are intended for SaaS hosts running IdentSphere as a multi-tenant platform — most B2B SaaS apps don't need this.
What RBAC does NOT do
- Field-level ACLs (only resource-level).
- Time-bounded grants.
- Approval workflows.
These can all be layered on top using the extensions field on AuthUser
plus host-side middleware.