Keystone OpenIddict Spike — Scope
Status: Scoping only — not started. This is the answer to item 2 in keystone-framing.md Section 10 ("a concrete estimate... this is the Side 2 OpenIddict spike"). Worked out 2026-08-22, in the same conversation that resolved the entitlement-delegation question below.
Deadline context: part of the ~4 months of comfortable runway inside the January 2027 decision deadline set in keystone-framing.md Section 8.
Read first: keystone-external-login-proposal.md for the actual code patterns (OpenIddict config, the linking-not-coupling ExternalLogins model, the FastEndpoints login/callback endpoints) — this document is the scope and boundaries around that proposal, not a replacement for it.
Companion tracking document: keystone-spike-build-log.md — a running, dated log of the spike's actual build, one entry per item, covering real friction hit, decisions made, and time spent. This is the lived Side 2 evidence keystone-framing.md §5 item 1 calls for, comparable to entra-cost-tally.md's Side 1.
1. The three-piece split, decided
This spike doesn't happen in isolation — it's one piece of a three-way split that came out of walking through what "an admin app" and "a billing API" actually mean given what's already built:
- Keystone — a new, standalone service. Owns credentials (password hash or linked external identity), a stable person ID, and nothing else. Its own Clean Architecture solution (Core/UseCases/Infrastructure/Web), its own database — unlike Command Center, Keystone has real persistent state from day one.
- Command Center (
api.traxsgroup.com, already live) — grows into owning subscriptions, entitlement, and billing, per its own existing BRD ("unified billing hub," "platform analytics," both already scoped as its long-term vision, previously filed under "2028+"). Keystone delegates entitlement questions to Command Center rather than owning that data itself. Real architectural step up for Command Center, which has no database in v1 today — this isn't a small addition for it, even though it's the direction it was already headed. - One admin app (new) — a single React + TypeScript frontend (matching the Vite/Cloudflare Pages pattern already used for RoundTrip and Waypoint's web clients), not three separate ones. Talks to both Keystone (account/identity administration — replacing what Entra's admin center currently does, badly, per
entra-cost-tally.md's TRA-437) and Command Center (ops monitoring per TRA-386, and eventually billing/analytics). Authenticated through Keystone itself — a real, early test of the identity service on the one account that matters most while building it.
The admin app and Command Center's billing buildout are not part of this spike. They're named here so the spike is scoped against the real shape of where this is going, not built in a vacuum.
2. What the spike needs to prove
- OpenIddict issuing real tokens end to end for a test client — the central token-issuer role described in
keystone-framing.mdSection 9. - Email/password registration and login working — Keystone as primary credential owner, not Entra.
- The optional-federation pattern working against a real Entra app registration — "Sign in with Microsoft" as a deliberate, explicit choice, never the default path. This is what actually resolves TRA-389's root cause (home-tenant discovery only fires on a chosen action, not silently during registration) — worth re-confirming end to end, not just trusting the proposal doc's reasoning.
- The linking-not-coupling
ExternalLoginspattern, including the guardrails already specified in the proposal doc: verified-email-required linking, no silent account merging, and theTenantUser/Techniciansplit staying structurally incapable of cross-resolving. - A stable person ID that RoundTrip's
TenantUserscould reference by foreign key without restructuring — confirmed with a throwaway/test integration against a copy of the schema, not a real migration of production data. - The same FK pattern proven against Waypoint's
WaypointUsers— settled 2026-08-22 as small/mechanical (zero live users, no real data to migrate): aKeystoneUserIdcolumn replacesEntraObjectIdas the resolution key. Same throwaway/test-schema confirmation as item 5, not a real migration.
3. What's explicitly out of scope for the spike
Left out on purpose, so this stays a real spike — proving the mechanics work — rather than quietly growing into a full platform build before the bigger decision is even made:
- The admin app (Section 1) — not built here.
- Any real call to Command Center for entitlement — stub it. A hardcoded "yes" is enough to prove the shape of the delegation without needing Command Center's billing buildout to exist first. This is what keeps the spike decoupled from Command Center's own, separate roadmap.
- Production-grade account recovery, MFA, brute-force protection, or any of the admin tooling Entra/Keycloak provided for free (
keystone-framing.mdSection 5, item 1) — real work, but not what this spike is answering. - The actual RoundTrip credential migration (
keystone-framing.mdSection 5, item 4) — a separate, real, time-sensitive piece of work in its own right, not something to fold into a spike. - Waypoint's actual
EntraObjectId-keyed schema migration (keystone-framing.mdSection 9) — item 6 above proves the pattern works, but applying it for real to Waypoint's live schema is separate follow-through, not part of the spike. - Waypoint's
TenantId-pinned-to-the-shared-Entra-tenant gap (WAY-49) — a separate, Entra-independent workspace-resolution problem discovered while scoping item 6. Logged directly in Waypoint's own backlog, not part of this spike or this document's scope.
4. Sequencing
The spike does not need to wait on Command Center's billing/entitlement buildout (stubbed, per Section 3) or on the admin app (not needed to prove the core mechanics). It can start now, independent of those two pieces' own timelines. What does depend on the spike finishing: the "concrete estimate" item in keystone-framing.md Section 10 — this spike, run for real, is what turns that estimate from reasoning-in-the-abstract into an actual lived data point, the same way entra-cost-tally.md is the lived data point for Entra's side of the comparison.
5. How to test it
Not relying on manual click-through — each item in Section 2 maps to a specific kind of testing, and the tooling for all of it is free or open source. Researched and confirmed 2026-08-22.
- Protocol-level flow verification (Section 2, items 1 and 3 — token issuance, the optional-Entra-federation handshake): OAuth Tools (Curity, free) and OIDC Debugger (free) — both browser-based, both let you walk an actual authorization flow step by step and inspect the tokens and claims that come back. This is exactly the kind of check that would have caught Waypoint's
tid-vs-full-schema-URL claim surprise (infrastructure.md) before it hit production rather than after. Update, 2026-08-23: Side 2 is now underway.keystone-spike-build-log.mdis the running evidence file — dated entry per spike item, starting with item 1 (OpenIddict token issuance, complete as of this date). - Automated login/registration/recovery flows (Section 2, item 2, and the RoundTrip migration-readiness gate's "tested, not just built" account-recovery flow from
keystone-framing.mdSection 8): Playwright — free, open source, and already RoundTrip's existing E2E pattern, so this isn't a new tool to adopt, just an existing one pointed at a new target. Worth building this suite as real, versioned, re-runnable tests from the start, not one-off manual verification — it's also the natural place to prove the "set up your new login" user-communication flow works before it's ever run against a real customer. - JWT/token security (cuts across items 1 and 4 — relevant because Keystone becomes the one place a forged or tampered token compromises every product at once, per
keystone-framing.mdSection 5 item 3): jwt_tool — free, open source, built specifically to probe algorithm-confusion attacks, signature stripping, and claim tampering. - The
ExternalLoginslinking guardrails specifically (Section 2, item 4 — no silent account merging, noTenantUser/Techniciancross-resolution): not really an off-the-shelf-tool problem. This belongs as a real xUnit test suite written directly against the scenarios in the proposal doc's testing checklist (keystone-external-login-proposal.md, Section 5) — run every time, not verified by hand. - Broader auth-surface security scanning, for the production tier rather than the spike itself: OWASP ZAP — free, open source, the closest thing to an industry-standard baseline scanner, and can run in CI against the login/callback endpoints.
- Load/reliability, also production-tier rather than spike-critical, since an identity outage now takes the whole platform down at once: k6 — the core CLI tool is open source and free for any amount of local/CI load; only Grafana's hosted cloud add-on costs money, and that isn't needed here.