Skip to content

feat(hub): add Microsoft Entra OIDC authentication - #150

Open
alliscode wants to merge 57 commits into
alliscode-artifact-ingestion-layerfrom
alliscode-production-entra-oidc
Open

alliscode wants to merge 57 commits into
alliscode-artifact-ingestion-layerfrom
alliscode-production-entra-oidc

Conversation

@alliscode

@alliscode alliscode commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

Why

Replica Hub needs production sign-in that does not require every user to have a GitHub account. This adds a standards-based OpenID Connect path for a single Microsoft Entra tenant while keeping Hub membership as the persisted authority for installation access.

What changes

Operators can select one explicit user sign-in provider and configure a single-tenant Entra application. Hub performs OIDC discovery, authorization code exchange with PKCE, browser-bound state, nonce and replay checks, signed ID-token validation, bounded JWKS caching and rotation, and strict issuer, audience, authorized-party, and lifetime checks. The Entra issuer is limited to the expected tenant-specific Microsoft login URL, and long real-world Entra authorization codes use a separate safe callback bound from GitHub.

Hub.User and Hub.Administrator app roles control admission and administrator mapping. Hub stores identity by provider, tenant issuer, and immutable subject; login, email, name, and picture remain mutable display data. Just-in-time assignment or invitation-required admission can create membership, while suspended and removed memberships and the final-administrator rule remain Hub-owned protections. Provider tokens are discarded after identity and role extraction, and browser access continues through opaque Hub sessions.

flowchart LR
  User[User browser] --> Entra[Microsoft Entra ID]
  Entra --> OIDC[OIDC callback validation]
  OIDC --> Identity[External identity]
  Identity --> Membership[Hub membership and admission]
  Membership --> Session[Opaque Hub session]
  Session -. separate boundary .-> Source[GitHub source access]
  Session -. separate boundary .-> Prototype[Prototype authorization]
  Prototype -. separate workload identity .-> Artifact[Artifact publishing]
Loading

The included Microsoft Graph PowerShell script can preflight, plan, apply, or safely remove script-owned setup. It configures the callback, assignment requirement, app roles, and requested group assignments while preserving unrelated roles. The real GitHub and Entra pilot completed sign-in, bootstrap, session creation, and the long callback-code flow using manual portal configuration. The setup script is still being tested: its contract and PowerShell preflight were exercised, but the live tenant pilot did not use it to create the application, so operators and reviewers should inspect Plan output and intended tenant changes before Apply.

GitHub user authentication, GitHub source credentials, synchronized repository permissions, prototype authorization, and artifact workload credentials remain separate boundaries. This change does not add provider account linking, a provider chooser, SCIM, background Graph access, or refresh-token storage.

Storybook screenshots

Hub/Pages/Identity/Sign in — Signed out — dark theme — 1280 × 720

Hub sign-in signed-out story in dark theme at 1280 by 720

Hub/Pages/Identity/Sign in — Signed in — dark theme — 1280 × 720

Hub sign-in signed-in story in dark theme at 1280 by 720

Hub/Pages/Identity/Sign in — Unconfigured — dark theme — 1280 × 720

Hub sign-in unconfigured story in dark theme at 1280 by 720

Hub/Pages/Identity/Membership administration — Default — dark theme — 1280 × 720

Hub membership administration default story in dark theme at 1280 by 720

Copilot AI and others added 15 commits October 26, 2026 23:25
Add encrypted database and read-only environment credential providers for one GitHub installation, transactional identity repositories, and their storage contracts.

Co-authored-by: Ben Thomas <ben.thomas@microsoft.com>
Co-authored-by: Nishiki <hello@nshki.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@alliscode
alliscode requested review from a team and nshki as code owners October 28, 2026 19:10
Copilot AI auto review requested due to automatic review settings October 28, 2026 19:10
@alliscode

Copy link
Copy Markdown
Collaborator Author

The Entra setup script is still being tested. Please focus review on whether its Plan output, Apply convergence, assignment reconciliation, ownership checks, and repeat-run behavior are safe and idempotent before operators use it in a tenant.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved OIDC flaws can remove valid Entra memberships and sessions, preserve administrator access after a role downgrade, and accept ID tokens without expiration.

11 open issues
1 file not reviewed
  • hub/package-lock.json: Generated file
What changed in this PR

Adds single-tenant Microsoft Entra sign-in as an explicitly selected alternative to GitHub, while retaining Hub-owned membership and opaque browser sessions.

Changes:

  • Adds OIDC configuration, provider revisions, authorization flows, token validation, and app-role admission.
  • Updates authentication routes, session metadata, identity storage, and the sign-in interface for provider selection.
  • Adds Microsoft Graph setup tooling, supporting tests, and operator documentation.
File Description
hub/​server/​routes/​index.ts Registers OIDC initiation and callback routes.
hub/​server/​routes/​authentication.test.ts Covers callback bounds, validation, cookies, and log omission.
hub/​server/​routes/​api/​session/​get/​index.ts Exposes configured provider metadata.
hub/​server/​routes/​api/​auth/​oidc/​post/​index.ts Reuses protected sign-in initiation.
hub/​server/​routes/​api/​auth/​oidc/​callback/​get/​index.ts Applies the larger OIDC code limit.
hub/​server/​routes/​api/​auth/​github/​callback/​get/​index.ts Delegates to shared handling with GitHub’s code limit.
hub/​server/​routes/​api/​auth/​callback/​get/​index.ts Centralizes callback validation, cookies, and redirects.
hub/​server/​repositories/​external-identities/​types.ts Adds identity email attributes.
hub/​server/​repositories/​external-identities/​save-external-identity/​index.ts Refreshes stored email data.
hub/​server/​repositories/​authorization-attempts/​consume-attempt/​index.ts Accepts bootstrap and recovery purposes.
hub/​server/​repositories/​authentication-providers/​get-latest-revision/​index.ts Fetches the highest stored provider revision.
hub/​server/​integrations/​oidc/​create-client/​types.ts Defines OIDC configuration, client, and profile contracts.
hub/​server/​integrations/​oidc/​create-client/​index.ts Implements discovery, code exchange, and token verification.
hub/​server/​integrations/​oidc/​create-client/​index.test.ts Covers token validation, caching, rotation, and outages.
hub/​server/​domains/​identity/​create-store/​types.ts Adds latest-provider-revision lookup.
hub/​server/​domains/​identity/​create-records/​index.ts Binds the new revision query.
hub/​server/​domains/​authentication/​start-oidc-authorization/​index.ts Creates browser-bound OIDC authorization attempts.
hub/​server/​domains/​authentication/​read-oidc-configuration/​index.ts Validates the Entra environment profile.
hub/​server/​domains/​authentication/​read-oidc-configuration/​index.test.ts Covers configuration requirements and rejected values.
hub/​server/​domains/​authentication/​read-authentication-provider/​index.ts Requires explicit provider selection.
hub/​server/​domains/​authentication/​read-authentication-provider/​index.test.ts Tests supported and invalid provider values.
hub/​server/​domains/​authentication/​ensure-oidc-provider-revision/​index.ts Persists revisions and rejects configuration drift.
hub/​server/​domains/​authentication/​ensure-oidc-provider-revision/​index.test.ts Covers revision reuse, rollback, and credential fingerprints.
hub/​server/​domains/​authentication/​ensure-oidc-provider-revision/​index.db.test.ts Checks revision reuse after database-backed restart.
hub/​server/​domains/​authentication/​create-service/​types.ts Adds OIDC dependencies and provider metadata.
hub/​server/​domains/​authentication/​create-service/​oidc.test.ts Covers OIDC admission, membership lifecycle, and replay rejection.
hub/​server/​domains/​authentication/​create-service/​index.ts Dispatches authorization to the selected provider.
hub/​server/​domains/​authentication/​create-runtime/​index.ts Composes provider configuration and runtime clients.
hub/​server/​domains/​authentication/​complete-oidc-authorization/​index.ts Resolves identities, evaluates membership, and creates sessions.
hub/​script/​tests/​setup-entra-oidc.test.mjs Adds source-level setup-script contract checks.
hub/​script/​setup-entra-oidc.ps1 Adds Graph preflight, planning, application, and owned-resource removal.
hub/​schema/​migrations/​20261027221500_oidc_identity_attributes/​migration.sql Adds nullable external-identity email storage.
hub/​schema/​external-identity.prisma Models the email attribute.
hub/​README.md Updates Hub’s authentication and feature overview.
hub/​package.json Adds the jose dependency.
hub/​package-lock.json Locks the new dependency.
hub/​docs/​README.md Links the Entra operator guide.
hub/​docs/​membership-and-administration.md Documents OIDC admission and lifecycle boundaries.
hub/​docs/​identity.md Describes provider selection and OIDC identity contracts.
hub/​docs/​entra-oidc.md Documents setup, configuration, roles, and lifecycle limits.
hub/​docs/​development.md Explains provider selection for local development.
hub/​docs/​architecture.md Reflects configured-provider authentication in Hub’s architecture.
hub/​app/​javascript/​pages/​sign-in-page/​types.ts Adds the provider-label presentation prop.
hub/​app/​javascript/​pages/​sign-in-page/​stories.tsx Uses an enterprise sign-in label in story fixtures.
hub/​app/​javascript/​pages/​sign-in-page/​index.tsx Renders provider-aware sign-in copy.
hub/​app/​javascript/​pages/​sign-in-page/​index.test.tsx Tests provider labels and unconfigured behavior.
hub/​app/​javascript/​application/​authentication/​index.tsx Uses session metadata to select sign-in initiation.
hub/​.env.example Adds explicit provider selection and OIDC configuration examples.

Review effort: Max (auto)

Comment thread hub/server/domains/authentication/complete-oidc-authorization/index.ts Outdated
Comment thread hub/server/integrations/oidc/create-client/index.ts
Comment thread hub/script/setup-entra-oidc.ps1 Outdated
Comment thread hub/script/setup-entra-oidc.ps1 Outdated
Comment thread hub/server/domains/authentication/create-runtime/index.ts
Comment thread hub/server/domains/authentication/start-oidc-authorization/index.ts
Comment thread hub/server/routes/index.ts Outdated
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@alliscode
alliscode force-pushed the alliscode-production-entra-oidc branch from 48021df to 6d9e822 Compare October 28, 2026 21:19
@alliscode
alliscode requested an auto review from Copilot October 28, 2026 22:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved schema, audit-context, and identity-lookup defects can roll back first-time and role-changing sign-ins and cause returning users to receive 500 errors after client-ID changes.

11 open issues
11 resolved since last review
1 file not reviewed
  • hub/package-lock.json: Generated file

Review effort: Max (auto)

Comment thread hub/server/domains/authentication/complete-oidc-authorization/index.ts Outdated
Comment thread hub/docs/identity.md Outdated
Comment thread hub/script/setup-entra-oidc.ps1 Outdated
Comment thread hub/script/setup-entra-oidc.ps1 Outdated
Comment thread hub/script/tests/setup-entra-oidc.test.mjs
Comment thread hub/server/domains/authentication/complete-oidc-authorization/index.ts Outdated
Comment thread hub/server/domains/authentication/create-runtime/index.ts Outdated
Comment thread hub/server/domains/authentication/read-oidc-configuration/index.ts
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@alliscode
alliscode requested an auto review from Copilot October 28, 2026 22:56
Ben Thomas and others added 2 commits October 29, 2026 08:09
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

PowerShell turns empty claim collections into null, causing Entra OIDC application creation and existing-application Plan/Apply flows to fail.

1 open issue
2 resolved since last review
1 file not reviewed
  • hub/package-lock.json: Generated file

Review effort: Max (auto)

Comment thread hub/app/javascript/application/authentication/index.tsx
Ben Thomas and others added 19 commits October 29, 2026 08:42
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@alliscode
alliscode force-pushed the alliscode-production-entra-oidc branch from ffec328 to 12b0b5e Compare October 29, 2026 15:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Human assessment is needed to evaluate credential-exposure and membership-audit risks that are not covered by the published review.

No open issues 🎉

1 resolved since last review
1 file not reviewed
  • hub/package-lock.json: Generated file

Review effort: Max (auto)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants