Vitrolife Group: Hybrid Entra + OpenFGA authorization for a .NET healthcare platform
The Vitrolife Group is a Swedish medical-device and software company serving IVF clinics worldwide. Its internal metadata platform — built on .NET 10 to organize landing zones, domains, platforms, and teams — uses a hybrid authorization design: Microsoft Entra ID app roles for coarse-grained access and OpenFGA for fine-grained, per-resource decisions.
At a glance
| Industry | Healthcare / medical devices (IVF) |
| Stack | .NET 10, ASP.NET Core, Microsoft Entra ID, Wolverine, Aspire |
| Use case | Internal metadata platform: landing zones, domains, platforms, teams |
| Deployment | Self-hosted alongside the .NET API |
| Key features used | Contextual tuples, intersections, conditions, full + differential sync from OpenFGA |
Why OpenFGA
Entra ID gave Vitrolife a managed identity layer for both human users and service principals, but app roles alone could not express per-resource permissions ("can edit this landing zone, not all of them"). The platform team layered OpenFGA underneath to model ownership and group membership without inventing a parallel directory.
Crucially, the team wanted OpenFGA — not Entra — to be the source of truth for access groups, so that the application's own model of "who has access to what" did not depend on a directory operation in a separate system.
Architecture
- App-role grammar. Every Entra app role follows
<api>.<resource>.<capability>.<qualifier>. Capabilities areviewer/editor/admin. The qualifier is eitherall(the principal may act on every record of that resource) orself(the principal may act only on records they have an OpenFGA relationship with).allinjects a contextual tuple at request time;selffalls through to a normal Check against the relationship graph. - Users and service principals are uniform. Because both human users and service principals carry app roles, the application code never branches on principal type — the OpenFGA tuple set treats them identically.
- Type-safe C# wrappers.
FGAObjectIdenforces<type>:<id>shape at compile time. AnFGATuplebuilder makes tuple construction explicit, and relations are modeled assnake_caseenums to match the OpenFGA wire format without stringly-typed bugs. - Group memberships as contextual tuples. Entra group memberships are surfaced into OpenFGA via contextual tuples on each request, intersected with FGA group definitions so a principal must satisfy both the Entra group and the FGA relationship to gain access.
- Atomic writes via transactional outbox. SQL writes and OpenFGA tuple writes are coordinated through a Wolverine outbox: the database row and the queued FGA mutation commit together; consumers process the outbox to make the tuple change visible. This is eventually consistent within a small, bounded window.
- OpenFGA → Entra sync. A scheduled job reads OpenFGA as the source of truth and reconciles Entra access groups: an hourly full sync plus a differential sync triggered by outbox events. If a tuple is removed in OpenFGA, the corresponding Entra membership is removed on the next pass.
- Vertical slices and Aspire local dev. Features are organized as vertical slices; .NET Aspire orchestrates a local environment with a mocked Microsoft Graph and a local OpenFGA, so the team can run the full authorization path end-to-end on a developer laptop.
Outcomes
- One mental model for authorization that spans humans, service principals, and resources, with Entra handling identity and OpenFGA handling relationships.
- Per-resource permissions without a custom directory — the existing Entra investment stays in place.
- OpenFGA as the durable source of truth for access groups, with Entra reconciled on a schedule rather than the other way around.
- Atomic SQL + tuple writes through the Wolverine outbox, removing the class of bugs where the application data and the access graph drift apart.
Source
This case study is based on a presentation in the OpenFGA community meeting by Simon Gottschlag, CTO at Co-native, working with the Vitrolife Group on its platform.