नोट
इस पेज तक पहुँच के लिए प्रमाणन की आवश्यकता होती है. आप साइन इन करने या निर्देशिकाओं को बदलने का प्रयास कर सकते हैं.
इस पेज तक पहुँच के लिए प्रमाणन की आवश्यकता होती है. आप निर्देशिकाओं को बदलने का प्रयास कर सकते हैं.
Fabric Apps uses the @role decorator to attach authorization rules directly to your data models. Permissions are type-safe, refactor-friendly, and automatically compiled into the underlying data access configuration.
Before you begin
- Understand the difference between authentication (who you are) and authorization (what you can do)
- Review Configure authentication to set up identity verification
- Understand Data models overview for entity basics
Built-in roles
Fabric Apps recognizes the built-in authenticated role. You can also define custom roles in your policies when needed.
| Role | Description | Use case |
|---|---|---|
authenticated |
Requires a valid user session with Fabric authentication | User-specific data, protected resources |
The @role decorator
Apply @role at the class level to control which roles can perform which actions on an entity:
@role(roleName, actions, options?)
Parameters
| Parameter | Type | Description |
|---|---|---|
roleName |
string |
The role name, such as 'authenticated' or a custom application role |
actions |
string \| string[] |
Single action or array: 'create', 'read', 'update', 'delete', or '*' for all |
options |
object |
Optional object with check, include, and exclude properties |
Basic example
Restrict authenticated users to their own data:
import { entity, role, uuid, text } from '@microsoft/rayfin-core';
@entity()
@role('authenticated', ['create', 'read', 'update', 'delete'], {
policy: (claims, item) => claims.sub.eq(item.userId),
})
export class Todo {
@uuid() id!: string;
@text() title!: string;
@text({ optional: true }) description?: string;
@text() userId!: string;
}
In this example:
- Authenticated users can access only Todo items where
userIdmatches their JWTsubclaim.
Type-safe policy expressions
The policy callback provides typed access to both claims and entity fields. TypeScript infers the entity type from the decorated class, giving you autocompletion and refactor safety:
policy: (claims, item) => claims.sub.eq(item.userId)
Supported claims
| Claim | Description | Example value |
|---|---|---|
claims.sub |
Subject identifier (user ID) | 00000000-0000-0000-0000-000000000001 |
claims.email |
User email address | user@contoso.com |
claims.role |
User role (if provided by identity provider) | admin |
Expression operators
| Operator | Example | Description |
|---|---|---|
.eq() |
claims.sub.eq(item.userId) |
Equality check |
Logical operators
Combine expressions with .and() and .or():
// User must own the item AND item must be active
@role('authenticated', 'read', {
policy: (claims, item) =>
claims.sub.eq(item.userId).and(item.isActive.eq(true))
})
// User is admin OR user owns the item
@role('authenticated', ['update', 'delete'], {
policy: (claims, item) =>
claims.role.eq('admin').or(claims.sub.eq(item.ownerId))
})
Both sides are parenthesized automatically for correct grouping.
Field-level permissions
Specify the fields a role can access using include or exclude in the role options.
Include specific fields
Only allow the title field during create operations:
@entity()
@role('authenticated', 'create', {
policy: (claims, item) => claims.sub.eq(item.createdBy),
include: ['title'],
})
export class Document {
@uuid() id!: string;
@text() title!: string;
@text({ optional: true }) content?: string;
@text() createdBy!: string;
}
Exclude specific fields
Hide sensitive fields from read operations:
@entity()
@role('authenticated', 'read', {
exclude: ['lastLogin', 'passwordHash'],
})
export class User {
@uuid() id!: string;
@text() email!: string;
@date({ optional: true }) lastLogin?: Date;
@text() passwordHash!: string;
}
Note
Field arrays are typed to the entity's actual property names. Renaming a field produces a compile-time error in every include or exclude list that references it.
Action-specific permissions
Apply different rules per action using multiple @role decorators:
@entity()
@role('authenticated', 'create', {
policy: (claims, item) => claims.sub.eq(item.createdBy),
include: ['title', 'content'],
})
@role('authenticated', 'read', {
policy: (claims, item) => claims.sub.eq(item.createdBy),
})
@role('authenticated', 'update', {
policy: (claims, item) => claims.sub.eq(item.createdBy),
exclude: ['adminNotes'],
})
@role('authenticated', 'delete', {
policy: (claims, item) => claims.sub.eq(item.createdBy),
})
export class SecureDocument {
@uuid() id!: string;
@text() title!: string;
@text({ optional: true }) content?: string;
@text({ optional: true }) adminNotes?: string;
@text() createdBy!: string;
}
This configuration:
- Create: Only the creator can create, and only
titleandcontentfields are allowed. - Read: Only the creator can read their own documents.
- Update: Only the creator can update, but they can't modify
adminNotes. - Delete: Only the creator can delete.
How permissions work
- Metadata collection: The
@roledecorator collects permission metadata when the class is defined. - Schema generation: When you run
db apply, the CLI reads metadata and generates permission configuration. - Policy compilation: TypeScript policy callbacks are compiled into data access policy expressions (for example,
@claims.sub eq @item.userId). - Runtime enforcement: The data access layer enforces permissions on every API request.
- Conflict detection: Multiple
@roledecorators on the same class are aggregated per role, with warnings for conflicting declarations.
Common patterns
Owner-only access
@entity()
@role('authenticated', '*', {
policy: (claims, item) => claims.sub.eq(item.ownerId)
})
export class PrivateNote {
@uuid() id!: string;
@text() ownerId!: string;
@text() content!: string;
}
Full access for authenticated users
@entity()
@role('authenticated', '*')
export class BlogPost {
@uuid() id!: string;
@text() title!: string;
@text() content!: string;
}
Admin override
@entity()
@role('authenticated', ['create', 'read', 'update'], {
policy: (claims, item) =>
claims.role.eq('admin').or(claims.sub.eq(item.ownerId))
})
@role('authenticated', 'delete', {
policy: (claims, _item) => claims.role.eq('admin')
})
export class ManagedResource {
@uuid() id!: string;
@text() ownerId!: string;
@text() name!: string;
}
Admins can modify any resource, but only admins can delete.
Next steps
- Configure authentication to set up identity providers
- Query data with GraphQL to test permission-protected queries
- CLI command reference for schema generation commands