Skip to content

Drive affordances from roles

The session carries advisory roles. Use platform.hasRole(role) to decide whether to show an affordance. Roles can change mid-session — a grant, a sign-in — so re-evaluate on session.changed.

invoice-actions.ts
import { Component, CUSTOM_ELEMENTS_SCHEMA, inject, signal } from "@angular/core";
import type { Session } from "@platform/sdk";
import { PLATFORM } from "../shared/platform.token";
// Driving affordances from roles. hasRole() reads the advisory roles in the session snapshot — it is
// for show/hide ONLY; the backend re-checks on every request and is the real gate. Roles can change
// mid-session, so re-evaluate on session.changed.
@Component({
selector: "invoice-actions",
schemas: [CUSTOM_ELEMENTS_SCHEMA],
template: `
@if (canViewInvoices()) {
<ds-button (click)="openInvoices()">View invoices</ds-button>
}
`,
})
export class InvoiceActions {
private readonly platform = inject(PLATFORM);
protected readonly canViewInvoices = signal(false);
constructor() {
this.refresh();
this.platform.subscribe<Session>("session.changed", () => this.refresh());
}
private refresh(): void {
this.canViewInvoices.set(this.platform.hasRole("invoices:read"));
}
protected openInvoices(): void {
// The backend still authorizes the actual read — this button only decides whether to show it.
}
}

This is the entire authentication surface an app author touches. The session cookie, the introspection the backend performs, and the role enforcement all happen below the SDK and are out of your app’s hands — by design. For the reasoning, see Advisory auth vs the backend gate.