Reference
FGA API Reference
Complete method reference for CheckAccess, GetAuthorizationFilter, CreateResource, PagedSpec, and more.
Complete reference for every public method in the FGA module.
ISqlOSFgaAuthService#
The core authorization service. Injected via DI as ISqlOSFgaAuthService.
CheckAccessAsync#
Check if a subject has access to a specific resource with a given permission. Walks up the resource hierarchy from the target resource to the root, looking for grants whose role includes the required permission.
var access = await authService.CheckAccessAsync(subjectId, "CHAIN_VIEW", "chain-1");
if (!access.Allowed)
return Results.Json(new { error = "Permission denied" }, statusCode: 403);Parameters
| Name | Type | Description |
|---|---|---|
subjectId | string | The subject (user, agent, etc.) to check access for. |
permissionKey | string | The permission key to check (e.g., "CHAIN_VIEW"). |
resourceId | string | The resource ID to check access on. |
Returns
Task<SqlOSFgaAccessCheckResult>
| Field | Type | Description |
|---|---|---|
Allowed | bool | Whether the subject has the permission on the resource. |
Trace | List<SqlOSFgaAccessTrace>? | Step-by-step trace of how the decision was made. |
Error | string? | Error message if the check failed unexpectedly. |
HasCapabilityAsync#
Check if a subject has a specific permission at root level — i.e., anywhere in the resource tree. Use for global capability gates.
var canEdit = await authService.HasCapabilityAsync(subjectId, "CHAIN_EDIT");
if (!canEdit)
return Results.Json(new { error = "Permission denied" }, statusCode: 403);Parameters
| Name | Type | Description |
|---|---|---|
subjectId | string | The subject to check. |
permissionKey | string | The permission key to check. |
Returns
Task<bool> — true if the subject has any grant with a role that includes the permission.
GetAuthorizationFilterAsync#
Produce a LINQ expression that filters an IQueryable<T> to only entities the subject can access. The expression translates to a SQL Server table-valued function call at query time.
var filter = await authService
.GetAuthorizationFilterAsync<Chain>(subjectId, "CHAIN_VIEW");
var chains = await dbContext.Chains
.Where(filter)
.OrderBy(c => c.Name)
.ToListAsync();Parameters
| Name | Type | Description |
|---|---|---|
subjectId | string | The subject to filter for. |
permissionKey | string | The permission key that determines which resources are visible. |
Type constraint: T : IHasResourceId — the entity must expose a ResourceId property.
Returns
Task<Expression<Func<T, bool>>> — an EF Core-compatible expression you pass to .Where().
TraceResourceAccessAsync#
Produce a detailed, structured trace of a resource access decision. Shows every step of the hierarchy walk and which grants matched or didn't. Useful for debugging authorization issues.
var trace = await authService.TraceResourceAccessAsync(
subjectId, "chain-1", "CHAIN_VIEW");
// trace contains the full decision pathParameters
| Name | Type | Description |
|---|---|---|
subjectId | string | The subject to trace access for. |
resourceId | string | The target resource. |
permissionKey | string | The permission to trace. |
Returns
Task<SqlOSFgaResourceAccessTrace> — structured trace of the full decision.
SqlOSFgaConvenienceExtensions#
Extension methods that reduce endpoint boilerplate. Available via using SqlOS.Fga.Extensions.
CreateResource#
Create an SqlOSFgaResource in the hierarchy. Adds to the change tracker but does not call SaveChangesAsync. Returns the resource ID so you can assign it to your domain entity.
var resourceId = context.CreateResource(
parentId: "retail_root",
name: request.Name,
resourceTypeId: "chain"
);
var chain = new Chain { ResourceId = resourceId, Name = request.Name };
context.Chains.Add(chain);
await context.SaveChangesAsync();Parameters
| Name | Type | Required | Description |
|---|---|---|---|
context | ISqlOSFgaDbContext | Yes | The DbContext (called as extension method). |
parentId | string | Yes | Parent resource ID in the hierarchy. |
name | string | Yes | Display name for the resource. |
resourceTypeId | string | Yes | Resource type identifier (e.g., "chain", "location"). |
id | string? | No | Custom resource ID. If null, a GUID is generated. |
Returns
string — the resource ID (either the provided id or the auto-generated GUID).
AuthorizedDetailAsync#
Fetch a single entity by predicate, check authorization, and return the appropriate HTTP result in one call. Replaces the pattern of fetch → check → map → return.
return await authService.AuthorizedDetailAsync(
context.Chains.Include(c => c.Locations),
c => c.Id == id,
subjectId,
"CHAIN_VIEW",
chain => new ChainDetailDto
{
Id = chain.Id,
Name = chain.Name,
LocationCount = chain.Locations.Count
});Parameters
| Name | Type | Description |
|---|---|---|
authService | ISqlOSFgaAuthService | The auth service (called as extension method). |
query | IQueryable<TEntity> | The queryable to fetch from (can include .Include()). |
predicate | Expression<Func<TEntity, bool>> | Filter to find the single entity (e.g., c => c.Id == id). |
subjectId | string | The subject to authorize. |
permissionKey | string | The permission to check on the entity's resource. |
selector | Func<TEntity, TDto> | Maps the entity to a DTO for the response body. |
Type constraint: TEntity : class, IHasResourceId
Returns
Task<IResult> — one of:
| Condition | HTTP Result |
|---|---|
| Entity not found | 404 Not Found |
| Access denied | 403 { "error": "Permission denied" } |
| Access granted | 200 with the mapped DTO |
PagedSpec Builder#
Fluent builder for creating cursor-paginated, sorted, searchable, authorization-filtered queries.
PagedSpec.For#
Start building a paged specification. The idSelector identifies the unique tiebreaker column for cursor pagination.
var spec = PagedSpec.For<Chain>(c => c.Id)
.RequirePermission("CHAIN_VIEW")
.SortByString("name", c => c.Name, isDefault: true)
.SortByString("description", c => c.Description ?? "")
.Search(search, c => c.Name, c => c.Description)
.Configure(q => q.Include(c => c.Locations))
.Build(pageSize, cursor, sortBy, sortDir);Builder Methods
| Method | Parameters | Description |
|---|---|---|
For<T>(idSelector) | Expression<Func<T, string>> | Start builder with the ID/tiebreaker column. |
.RequirePermission(key) | string | Set the FGA permission key for authorization filtering. |
.SortByString(name, selector, isDefault?) | string, Expression<Func<T, string>>, bool | Register a named string sort column. |
.Search(search, ...fields) | string?, params Expression<Func<T, string>>[] | Add text search across the given fields. |
.Where(predicate) | Expression<Func<T, bool>> | Add a static filter. |
.Configure(action) | Action<IQueryable<T>> | Configure the query (e.g., .Include()). |
.Build(pageSize, cursor, sortBy, sortDir) | int, string?, string?, string? | Build the final PagedSpecification<T>. |
ISpecificationExecutor#
Executes a PagedSpecification<T> against a queryable, combining user filters with FGA authorization and cursor pagination. Injected via DI.
ExecuteAsync#
Execute a paged specification and return a paginated result.
var result = await executor.ExecuteAsync(
context.Chains, spec, subjectId,
c => new ChainDto
{
Id = c.Id,
Name = c.Name,
LocationCount = c.Locations.Count
});
// result.Items — the page of DTOs
// result.NextCursor — pass to next request for pagination
// result.HasMore — whether more pages existParameters
| Name | Type | Description |
|---|---|---|
dbSet / query | DbSet<TEntity> or IQueryable<TEntity> | The base query. |
specification | PagedSpecification<TEntity> | The spec built by PagedSpec.For<T>().Build(). |
subjectId | string | The subject for FGA authorization filtering. |
selector | Func<TEntity, TDto> | Maps entities to DTOs. |
cancellationToken | CancellationToken | Optional cancellation token. |
Type constraint: TEntity : class, IHasResourceId
Returns
Task<PaginatedResult<TDto>>
| Field | Type | Description |
|---|---|---|
Items | List<TDto> | The current page of results. |
NextCursor | string? | Opaque cursor for the next page. null if no more pages. |
HasMore | bool | Whether additional pages exist. |
CountAsync#
Count total matching entities (with authorization filtering) without fetching data.
var total = await executor.CountAsync(context.Chains, spec, subjectId);Parameters
| Name | Type | Description |
|---|---|---|
dbSet | DbSet<TEntity> | The base query. |
specification | PagedSpecification<TEntity> | The spec. |
subjectId | string | The subject for authorization. |
Returns
Task<long> — total count of accessible, matching entities.
IHasResourceId#
Interface that connects domain entities to FGA resources. Required for GetAuthorizationFilterAsync, AuthorizedDetailAsync, and ISpecificationExecutor.
public interface IHasResourceId
{
string ResourceId { get; }
}Implementation
public class Chain : IHasResourceId
{
public string Id { get; set; } = Guid.NewGuid().ToString();
public string ResourceId { get; set; } = "";
public string Name { get; set; } = "";
}FGA Models#
SqlOSFgaAccessCheckResult#
public class SqlOSFgaAccessCheckResult
{
public bool Allowed { get; set; }
public List<SqlOSFgaAccessTrace>? Trace { get; set; }
public string? Error { get; set; }
}SqlOSFgaAccessTrace#
public class SqlOSFgaAccessTrace
{
public string Step { get; set; }
public string Detail { get; set; }
public string? ResourceId { get; set; }
public string? ResourceName { get; set; }
public string? GrantId { get; set; }
public string? RoleName { get; set; }
public string? SubjectName { get; set; }
}SqlOSFgaResource#
public class SqlOSFgaResource
{
public string Id { get; set; }
public string ParentId { get; set; }
public string Name { get; set; }
public string ResourceTypeId { get; set; }
public bool IsActive { get; set; }
}SqlOSFgaGrant#
public class SqlOSFgaGrant
{
public string Id { get; set; }
public string SubjectId { get; set; }
public string ResourceId { get; set; }
public string RoleId { get; set; }
public string? Description { get; set; }
}SqlOSFgaSubject#
public class SqlOSFgaSubject
{
public string Id { get; set; }
public string SubjectTypeId { get; set; }
public string DisplayName { get; set; }
public string? OrganizationId { get; set; }
public string? ExternalRef { get; set; }
}