Syncing Auth to FGA
Sync AuthServer users and memberships into FGA subjects and grants.
When using both AuthServer and FGA, you need to sync authenticated users into the FGA model so they can be authorized. The typical pattern is to sync on login.
The pattern
After login, ensure the user exists as an FGA subject, the organization exists as an FGA resource, and the membership is mapped to a grant:
public async Task EnsureUserAccessAsync(
string userId, string organizationId, CancellationToken ct)
{
var user = await _context.Set<SqlOSUser>()
.FirstAsync(x => x.Id == userId, ct);
var organization = await _context.Set<SqlOSOrganization>()
.FirstAsync(x => x.Id == organizationId, ct);
var membership = await _context.Set<SqlOSMembership>()
.FirstAsync(x => x.UserId == userId
&& x.OrganizationId == organizationId
&& x.IsActive, ct);
await EnsureSubjectAsync(user, organizationId, ct);
await EnsureOrganizationResourceAsync(organization, ct);
await EnsureMembershipGrantAsync(userId, organizationId, membership.Role, ct);
}
What each step does
EnsureSubjectAsync -- creates or updates SqlOSFgaSubject and SqlOSFgaUser for the authenticated user.
EnsureOrganizationResourceAsync -- creates an SqlOSFgaResource for the organization under root (if it doesn't exist).
EnsureMembershipGrantAsync -- creates a grant linking the user to a role on the organization resource, mapping the auth membership role to an FGA role:
| Auth role | FGA role |
|---|---|
admin or owner | org_admin (full access) |
| everything else | org_member (read access) |
When to call
Call EnsureUserAccessAsync after successful login, during token creation:
if (!string.IsNullOrWhiteSpace(tokens.OrganizationId))
{
await fgaService.EnsureUserAccessAsync(
user.Id, tokens.OrganizationId, ct);
}
The example app calls this in the token response helper, so every login automatically ensures the user has the right FGA grants based on their auth membership.
Why sync instead of query auth directly?
FGA subjects and grants are stored in tables optimized for the authorization query (tree walk + table-valued function). By syncing auth data into FGA at login time, authorization checks run entirely in SQL without joining against auth tables at query time.