Skip to main content

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

IndustryHealthcare / medical devices (IVF)
Stack.NET 10, ASP.NET Core, Microsoft Entra ID, Wolverine, Aspire
Use caseInternal metadata platform: landing zones, domains, platforms, teams
DeploymentSelf-hosted alongside the .NET API
Key features usedContextual 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 are viewer / editor / admin. The qualifier is either all (the principal may act on every record of that resource) or self (the principal may act only on records they have an OpenFGA relationship with). all injects a contextual tuple at request time; self falls 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. FGAObjectId enforces <type>:<id> shape at compile time. An FGATuple builder makes tuple construction explicit, and relations are modeled as snake_case enums 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.