Angular SDK
August 1, 2026 · View on GitHub
The RuleGate Angular SDK provides fail-closed user-interface helpers for a frontend authorization projection.
Install the stable release from npm:
pnpm add @fotbiler/rulegate-angular@1.0.0 @fotbiler/rulegate-client@1.0.0
Important
Route guards and template visibility are user-experience controls. Browser state is not trusted, and every protected backend operation must perform its own authorization check.
Package scope
The package provides:
RuleGateAuthorizationClientfor holding the current frontend projection- Declarative route metadata and a shared route guard
- Application-defined denied-navigation handling
- Permission, policy, and role route-guard factories for direct checks
- Standalone visibility and disabled-state directives
- Deterministic TypeScript constants generated from
rulegate.yaml - Public TypeScript models for snapshots and requirements
The modern package supports Angular 20–22. Angular 12–19 applications use
@fotbiler/rulegate-angular-legacy; Angular 9–11 applications consume the
framework-independent @fotbiler/rulegate-client through a small host-owned
service. See Frontend compatibility for the full
matrix, installation, and legacy support policy.
Supply authorization state
Load the current user's frontend authorization projection through application code and replace the complete snapshot:
import { inject } from '@angular/core';
import { RuleGateAuthorizationClient } from '@fotbiler/rulegate-angular';
const authorization = inject(RuleGateAuthorizationClient);
authorization.replaceSnapshot({
permissions: ['documents.read'],
policies: ['documents-read'],
roles: ['documents.reader'],
});
Call clear() during sign-out and before changing identities. The client
copies and deduplicates accepted identifiers. An invalid identifier rejects
the complete snapshot and clears all grants.
Protect routes
Use ruleGateRouteData with the shared ruleGateGuard to keep authorization
requirements visible in route configuration:
import { Routes } from '@angular/router';
import { ruleGateGuard, ruleGateRouteData } from '@fotbiler/rulegate-angular';
import { RuleGateIdentifiers } from './generated/rulegate';
export const routes: Routes = [
{
path: 'documents',
loadComponent: () => import('./documents/documents.component'),
canActivate: [ruleGateGuard],
data: ruleGateRouteData({
permission: RuleGateIdentifiers.permissions.documentsRead,
}),
},
];
Missing or malformed route metadata denies directly. A valid denied requirement uses the application's denied-navigation handler. Without a configured handler, navigation is cancelled.
Register a handler when denied navigation should redirect:
import { ApplicationConfig, inject } from '@angular/core';
import { RedirectCommand, Router } from '@angular/router';
import { provideRuleGateDeniedNavigation } from '@fotbiler/rulegate-angular';
export const appConfig: ApplicationConfig = {
providers: [
provideRuleGateDeniedNavigation(() => {
const router = inject(Router);
return new RedirectCommand(router.parseUrl('/forbidden'));
}),
],
};
The handler may return any Angular guard result, including false, a
UrlTree, or a RedirectCommand. The permission, policy, and role guard factories
remain available for routes that do not use declarative metadata.
Control template visibility
Import the standalone directive and pass one permission, policy, or role:
import { Component } from '@angular/core';
import { RuleGateCanDirective } from '@fotbiler/rulegate-angular';
import { RuleGateIdentifiers } from './generated/rulegate';
@Component({
selector: 'app-document-actions',
imports: [RuleGateCanDirective],
template: `
<button *ruleGateCan="{ permission: permissions.documentsWrite }; else unavailable">
Edit document
</button>
<ng-template #unavailable>Editing is unavailable.</ng-template>
`,
})
export class DocumentActionsComponent {
readonly permissions = RuleGateIdentifiers.permissions;
}
The directive renders the protected view only while the requirement is
granted. Its optional else template is rendered while state is uninitialized,
cleared, malformed, or denied.
Disable interactions
Use RuleGateDisableDirective when an action should remain visible but disabled:
import { Component } from '@angular/core';
import { RuleGateDisableDirective } from '@fotbiler/rulegate-angular';
import { RuleGateIdentifiers } from './generated/rulegate';
@Component({
selector: 'app-document-delete',
imports: [RuleGateDisableDirective],
template: `
<button type="button" [ruleGateDisable]="{ permission: permissions.documentsDelete }">
Delete document
</button>
`,
})
export class DocumentDeleteComponent {
readonly permissions = RuleGateIdentifiers.permissions;
}
Native controls receive their disabled property. Other interactive hosts
receive aria-disabled, expose data-rulegate-disabled, and have denied click
activation blocked. Keyboard and focus behavior for custom controls remains an
application responsibility.
Generate TypeScript identifiers
The npm package includes rulegate-angular, which generates deterministic
TypeScript constants from the manifest's policies, permissions, roles,
resource types, and actions:
pnpm exec rulegate-angular generate \
./rulegate.yaml \
--output ./src/app/generated/rulegate.ts
Verify committed output in CI without modifying it:
pnpm exec rulegate-angular generate \
./rulegate.yaml \
--output ./src/app/generated/rulegate.ts \
--check
Generation sorts identifiers ordinally, rejects generated-name collisions, writes files atomically, and uses byte-exact stale-output detection. Run the backend RuleGate CLI validation as the authoritative full-manifest check. The TypeScript generator validates the identifier-bearing manifest shape needed for generation; generated constants reduce drift but do not prove that the current user is authorized.
Backend-only requirement kinds such as attribute comparisons, time and date-time windows, context age, and canonical context policies are recognized without generating frontend grants from them. This lets the same manifest drive backend authorization and frontend identifiers while preserving the backend as the authorization boundary.
Fail-closed behavior
- Uninitialized and cleared state denies every check.
- Empty, non-string, or whitespace-padded identifiers invalidate a snapshot.
- Matching is exact and case-sensitive.
- Replacing a snapshot replaces every prior grant.
- Missing or invalid route metadata denies navigation.
- Invalid directive requirements render no protected content and keep disabled hosts denied.
- Client-side checks never replace backend authorization.
Read the security model for the complete trust boundary.
Optional Keycloak adapter
Applications using Keycloak can import the optional
@fotbiler/rulegate-angular/keycloak secondary entrypoint. The primary Angular
entrypoint has no keycloak-js dependency and remains provider-independent.
See the Keycloak integration guide for session synchronization, canonical realm and client role names, and the matching ASP.NET Core package.