/projects/dietbox-b2c
← All projectsDietbox B2C
One identity backbone, two audiences, custom sign-in journeys.
Senior Software Engineer, then Head of Technology · 2021–2024

Overview
One Azure AD B2C identity system carrying two audiences that share nothing but the account: a nutritionist subscribing and paying, and a patient arriving by invitation from the one treating them. Three years of custom sign-in journeys, federated providers, silent migration off the legacy store, and session revocation that reaches every open browser.
What I did
This is the author’s largest personal ownership in the Dietbox estate: half the commits over three years, across both audiences’ sign-in journeys.
- The two policy sets — one for the practitioner, one for the patient — each its own sign-up, sign-in and password-reset journey.
- Federation with Google, Facebook and Apple, each mapped through its own exchange profile into a common subject claim.
- The first-sign-in migration that moves a legacy-store user into the directory during the same journey they log in with.
- Session revocation: a stamp on the user compared against the token’s issue time, so a password change or an admin revoke signs the account out everywhere.
- The custom sign-in pages, one set per audience, served and filled in at runtime.
The problem
A hosted login gives a product one journey. This one needed several: a subscriber signing up and paying, a patient arriving by invitation with no password to set, an academy student, and a receptionist acting on someone else’s behalf — all over one directory, without four separate user stores to keep in sync.
By the numbers
The line count is a plain line count over the committed policy files; the commit share comes from the repository.
Architecture
Two independent policy sets sit above one directory, and everything downstream trusts the tokens they issue.
- Practitioner policiesSign-up, sign-in, subscriber and academy journeys for the nutritionist audience.
- Patient policiesSign-up and sign-in for the patient audience, invited rather than self-registering.
- DirectoryOne user store beneath both policy sets, holding local and federated accounts alike.
- Auth serviceValidates the tokens this system issues. Reads and writes against the directory itself go through a shared gateway package that several services in the platform take a dependency on.
- Custom UI pagesStatic markup, one set per audience, served by the identity platform and filled in at runtime.
The sign-in journey
Every step below corresponds to a technical profile that exists in the policy — this is the orchestration as written, not a simplification of it.
- Sign-inLocal credentials, or a federated provider — Google, Facebook or Apple — exchanged into a common subject claim.
- Legacy checkIs this a legacy-store user who has not yet been migrated?
- MigrationIf so, the account is written into the directory with an alternative security identifier linking it back to the legacy credential — in the same journey as the sign-in, not a separate step.
- EntitlementIs the account enabled, and does it belong to a gated journey — subscriber, academy — that requires an active entitlement?
- TokenA token is issued, stamped with the time the user’s security record was last valid from.
What it does
- Federated sign-in with three providers, each exchanged into a common subject claim.
- Silent migration off the legacy store during the user’s own sign-in journey.
- Per-audience branded pages, one set for the practitioner and one for the patient.
- Entitlement gates for subscriber and academy journeys, enforced inside the sign-in flow rather than after it.
Engineering decisions
Custom policies instead of a hosted login
A hosted login gives one journey. This product needed a subscriber signing up and paying, a patient arriving by invitation, an academy student, and a receptionist — over one directory, without four user stores to keep in sync. Writing the policy directly was the only way to get gated journeys and a first-sign-in migration without forking the user base.
Migration as a side effect of signing in
Nobody was asked to reset a password or re-register. The user experiences a login; the system experiences a migration, writing the account into the directory and linking it back to the legacy credential in the same journey.
Revocation that reaches open sessions
A token that is merely unrenewable is not revoked. Comparing the token’s issue time against a stamp on the user record is what makes "sign this account out everywhere" actually mean it, rather than "stop this account from getting a new token next time."
One directory, several journeys
Separate policies per audience over one shared user store, rather than one policy branching on audience or several stores that would have to be reconciled. The audiences share an identity, not a form.