Azure AD / Entra ID Integration
Register BizFirstGO as an API application in Azure AD / Entra ID — configure app roles, group claims, and the optional groups overage flow for organizations with many groups.
Azure App Registration
Create App Registration
In Azure Portal → Microsoft Entra ID → App Registrations → New Registration.
Name: BizFirstGO API, Supported account types: Single tenant (or multi-tenant if needed).
Configure App ID URI
In Expose an API, set the Application ID URI to api://bizfirstgo. This becomes the audience in the access token.
Add App Roles
In App Roles, create roles that map to BizFirstGO roles:
Role: BizFirstGO.Admin — Display name: "BizFirstGO Admin"
Role: BizFirstGO.Manager — Display name: "BizFirstGO Manager"
Role: BizFirstGO.User — Display name: "BizFirstGO User"
Role: BizFirstGO.Viewer — Display name: "BizFirstGO Viewer"
Enable Group Claims (Optional)
In Token Configuration → Add groups claim. Choose Security Groups. For the access token, select Group ID (GUIDs). Note: if a user has >200 groups, the overage indicator appears instead of the groups list.
Configure BizFirstGO Tenant Claim
Add a Optional Claim for the access token: tid (Azure tenant ID). BizFirstGO can use this to derive the BizFirstGO tenant ID via a static mapping.
Azure AD Token Structure
// Decoded Azure AD access token
{
"iss": "https://login.microsoftonline.com/{aad-tenant-id}/v2.0",
"sub": "A1bC2-dEfG3-hIjK4-lMnO5", // OID (Object ID) — stable user identifier
"oid": "A1bC2-dEfG3-hIjK4-lMnO5", // same as sub in v2 tokens
"tid": "aad-tenant-id", // Azure AD tenant ID
"aud": "api://bizfirstgo",
"upn": "jane.smith@company.onmicrosoft.com",
"name": "Jane Smith",
"email": "jane.smith@company.com",
"roles": ["BizFirstGO.Admin", "BizFirstGO.Manager"], // App roles
"groups": [ // Security group GUIDs (if <200 groups)
"a1b2c3d4-...", "e5f6g7h8-..."
]
}
BizFirstGO Federation Configuration
POST /passport/admin/tenants/{tenantId}/federation
{
"providerId": "azure-ad",
"displayName": "Microsoft Entra ID",
"issuer": "https://login.microsoftonline.com/{aad-tenant-id}/v2.0",
"jwksUri": "https://login.microsoftonline.com/{aad-tenant-id}/discovery/v2.0/keys",
"audience": "api://bizfirstgo",
"tenantIdConfig":{
"source": "static",
"value": "tenant-abc" // or use "claim" source with "tid" claim + mapping table
},
"userIdClaim": "oid", // Object ID — more stable than "sub" for Azure AD
"emailClaim": "email",
"rolesClaim": "roles", // App roles preferred over group GUIDs
"roleMapping": {
"BizFirstGO.Admin": "admin",
"BizFirstGO.Manager": "manager",
"BizFirstGO.User": "user",
"BizFirstGO.Viewer": "viewer"
}
}
Groups Overage Handling
Azure AD includes a maximum of 200 groups in JWT tokens. When a user has more than 200 groups, the token includes an overage indicator (_claim_names: { groups: "src1" }) instead of the groups list. BizFirstGO's Azure AD provider handles this automatically by calling Microsoft Graph.
// Overage token structure
{
"_claim_names": { "groups": "src1" },
"_claim_sources": {
"src1": {
"endpoint": "https://graph.microsoft.com/v1.0/users/{oid}/getMemberObjects"
}
}
}
// BizFirstGO Azure AD provider — automatic overage handling
public sealed class AzureADTokenProvider : IExternalTokenProvider
{
// When groups overage is detected, fall back to Graph API
private async Task<IList<string>> GetGroupsWithOverageAsync(
string userId, string accessToken, CancellationToken ct)
{
var graphClient = new GraphServiceClient(/* ... */);
var groups = await graphClient.Users[userId]
.TransitiveMemberOf
.GetAsync(ct: ct);
return groups?.Value?
.OfType<Group>()
.Select(g => g.Id ?? "")
.ToList() ?? [];
}
}
Azure AD security group claims contain GUIDs which are environment-specific (different in dev/staging/prod). App Roles use human-readable names (like BizFirstGO.Admin) and are portable across environments. Configure App Roles and use roleMapping instead of groupMapping for Azure AD integrations.