@apipass/permissions
v1.0.195
Published
Authorization UI primitives for Angular apps, the counterpart of the React `PermissionGate` / `useResourceActions` used in `account-manager`.
Downloads
608
Readme
@apipass/permissions
Authorization UI primitives for Angular apps, the counterpart of the React
PermissionGate / useResourceActions used in account-manager.
It provides:
PermissionsService— a hybrid orchestrator that decides between Cerbos and the legacy role model based on a per-app feature toggle.<apipass-permission-gate>— a render-prop component that, when blocked, shows the action disabled with an explanatory tooltip instead of hiding it.[apipassPermissionGate]— a lightweight attribute directive for native elements.
Design principles
These mirror the React PermissionGate:
- Never hide, always explain. A blocked action stays in the DOM, disabled,
with a tooltip telling the user why — it is not removed with
*ngIf. - Presentational. The gate does not decide permissions; it renders a
decision passed in via
isAllowed. The decision comes fromPermissionsService. - Fail-closed. With Cerbos enabled, any PDP failure denies every action.
Setup
Each app supplies one PermissionsConfig (how to read the Cerbos toggle, how to
build the principal, how to resolve legacy decisions) and wires everything with a
single providePermissions call:
// permissions-config.factory.ts — the only app-specific piece
export function permissionsConfigFactory(featureToggle: FeatureToggleService, iam: IamService): PermissionsConfig {
return {
cerbosEnabled: async () => (await featureToggle.getFeatures()).isCerbosEnabled(),
userInfo: async () => (await iam.getLoggedUserInfo()).cerbosUserInfo,
legacyResolver: async ({ kind, action }, ctx) => {
const { role } = await iam.getLoggedUserInfo()
// map { kind, action } → role.canX()
if (kind === 'flow' && action === 'read') return role.canAccessFlow((ctx as LegacyContext)?.projectId)
return false
}
}
}import { PermissionsModule, providePermissions } from '@apipass/permissions'
@NgModule({
imports: [PermissionsModule, /* ... */],
providers: [
providePermissions({
cerbosUrl: 'https://cerbos.example.com', // optional: registers CERBOS_SERVICE
configFactory: permissionsConfigFactory,
deps: [FEATURE_TOGGLE_SERVICE, IAM_SERVICE]
})
]
})
export class AppModule {}For a static config without DI, pass config instead of configFactory/deps
(or use the lower-level providePermissionsConfig).
HttpClient must be available (e.g. via provideHttpClient()), as required by
provideCerbos when cerbosUrl is set.
Adoption note: the config callbacks are inherently app-specific. Apps whose
UserInfodoes not exposecerbosUserInfoneed a small adapter building{ accountId, domain, roles }from their own user model.
Reading permissions
constructor(private readonly permissions: PermissionsService) {}
async ngOnInit() {
const flow = await this.permissions.checkResource({
kind: 'flow',
actions: ['read', 'update', 'stop'],
legacyContext: { projectId: this.projectId }
})
this.canEdit = flow.can('update')
this.canStop = flow.can('stop')
}Evaluate several kinds in one round-trip:
const result = await this.permissions.checkResources([
{ kind: 'stage', actions: ['approve', 'manage-roles'] },
{ kind: 'flow', actions: ['read', 'stop'], legacyContext: { projectId } }
])
result.can('stage', 'approve') // boolean
result.for('flow').can('stop') // booleanGating UI
Component (recommended for Angular Material)
<apipass-permission-gate [isAllowed]="canCreate" [noAccessLabel]="'PERMISSIONS.NO_CREATE' | translate">
<ng-template let-allowed>
<button mat-raised-button [disabled]="!allowed" (click)="allowed && create()">New</button>
</ng-template>
</apipass-permission-gate>The template receives allowed as its implicit context — the equivalent of the
React render-prop children(allowed).
Directive (native elements)
<button [apipassPermissionGate]="canCreate" noAccessLabel="No permission" (click)="create()">New</button>For Material controls prefer the component: Material reads its own disabled
@Input, not the DOM attribute the directive sets.
Public API
| Symbol | Kind | Description |
|---|---|---|
| PermissionsService | service | checkResource / checkResources, hybrid Cerbos + legacy |
| providePermissions / ProvidePermissionsOptions | fn / interface | One-call setup (config + service + optional Cerbos) |
| PERMISSIONS_CONFIG / providePermissionsConfig | token / fn | Lower-level per-app wiring |
| PermissionsConfig / LegacyCheck | interface | Config contract |
| PermissionGateComponent | component | <apipass-permission-gate> |
| PermissionGateDirective | directive | [apipassPermissionGate] |
| PermissionCheck | interface | { kind, actions, id?, legacyContext? } |
| PermissionResult / PermissionResultMap | interface | can(...) / for(kind) |
