RFC: Mentra-owned developer API keys (take WorkOS out of the publish path)#3289
RFC: Mentra-owned developer API keys (take WorkOS out of the publish path)#3289aisraelov wants to merge 1 commit into
Conversation
…ish path) Design-only proposal to issue + validate developer-console API keys in Core + our DB, replacing WorkOS-managed org API keys (workos().apiKeys.*). WorkOS stays for interactive login only. Covers the DeveloperOrgApiKey model, env-pinned hashed key format, local validation, a zero-downtime dual-stack migration, and open questions for review. Builds on the org roles gate in PR #3288.
📋 PR Review Helper📱 Mobile App Build⏳ Waiting for build... 🕶️ ASG Client Build⏳ Waiting for build... 🔀 Test Locallygh pr checkout 3289 |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit bc678b7. Configure here.
|
|
||
| - If the token starts with `msk_`, route to `authenticateMentraApiKey(token)`: | ||
| 1. Parse `env`, `keyId`, `secret`. Reject if `env !== <this Core's env>`. | ||
| 2. `findOne({ keyId, revokedAt: null })`. |
There was a problem hiding this comment.
Underscore key format ambiguity
High Severity
The proposed msk_<env>_<keyId>_<secret> layout and step to parse env, keyId, and secret conflicts with keyId documented as dak_<ulid>, which adds another underscore. A naive split on _ mis-identifies keyId and secret, so validation would reject valid keys.
Reviewed by Cursor Bugbot for commit bc678b7. Configure here.
| In `authenticateConsoleSession`, on the bearer path: | ||
|
|
||
| - If the token starts with `msk_`, route to `authenticateMentraApiKey(token)`: | ||
| 1. Parse `env`, `keyId`, `secret`. Reject if `env !== <this Core's env>`. |
There was a problem hiding this comment.
Env pin omits local
Medium Severity
The key format allows only dev, staging, and prod, but Core’s consoleEnvironmentLabel() also resolves local, debug, and other values. Minted keys and validation’s env !== this Core’s env check can disagree with local or debug deployments.
Reviewed by Cursor Bugbot for commit bc678b7. Configure here.
PR Agent Orchestrator State{
"cycle": 1,
"fixRound": 0,
"totalReviewerRuns": 1,
"consecutiveNoNewReviews": 1,
"openFindings": [],
"resolvedFindings": [],
"nitFindings": [],
"phase": "discovery",
"status": "in_progress",
"stagnationFixRounds": 0,
"fingerprintReopenCounts": {},
"mutedFingerprints": [],
"lastPair": [],
"lastOpenCount": 0
} |
🤖 PR Agent Review — cycle 1✅ No blocking findings · 0 blocking · 0 nits No model reviews ran this cycle. Updated automatically by the PR Agent Orchestrator each review cycle. Nits do not block merge. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bc678b776d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| 1. **Add, don't replace.** Ship Mentra-key issuance + validation **while still | ||
| accepting WorkOS keys** (keep the existing fallback). New keys created in the | ||
| console are Mentra keys; the list reads from our DB. |
There was a problem hiding this comment.
Keep legacy WorkOS keys revocable during migration
During the dual-stack window, this plan keeps existing WorkOS API keys valid but makes the console list read only from the new DB; the current console token surface discovers and revokes those WorkOS keys through GET/DELETE /console/tokens in cloud-v2/packages/core/src/api/console/cli-auth.api.ts lines 671-730. If a legacy key is leaked after Phase 2a, owners would no longer have a console path to find or revoke that still-valid credential, and surfacing it only as an optional read-only badge later does not restore revocation. Please make legacy WorkOS listing/revocation part of the dual-stack phase, or stop accepting legacy keys once they are hidden.
Useful? React with 👍 / 👎.
💡 Codex ReviewDuring the dual-stack window, this plan keeps existing WorkOS API keys valid but makes the console list read only from the new DB; the current console token surface discovers and revokes those WorkOS keys through ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |


Design-only RFC — no code in this PR. Companion to #3288 (console org roles).
Context
In Cloud V2 today, a developer's API key — the credential that publishes a miniapp to glasses headlessly / from CI — is a WorkOS-managed secret, created via
workos().apiKeys.createOrganizationApiKeyand validated on every request with a round-trip toworkos().apiKeys.createValidation. WorkOS is sitting in the critical publish path, not just login.This RFC proposes issuing + validating those keys ourselves in Core + our DB, and removing WorkOS from the publish path. Interactive
mentra loginstays on WorkOS.What's in the doc
cloud-v2/docs/issues/019-developer-api-keys/README.md:DeveloperOrgApiKeymodel in our DB — stores onlysha256(secret), never the secret.msk_<env>_<keyId>_<secret>— embeddedkeyIdmakes validation an indexed lookup; theenvprefix hard-fails cross-environment use and eases leak triage.authenticateConsoleSession— constant-time hash compare, throttledlastUsedAt, instantrevokedAtrevocation, no vendor round-trip.workos().apiKeys.*paths once telemetry shows no WorkOS-key validations.workosOrgIdvs first-classdeveloperOrgId), per-key scopes, key branding, legacy-key handling.Ask
Review the approach + answer the open questions. Once the direction is agreed, I'll implement Phase 2a (issuance + validation + WorkOS fallback) behind the existing API so nothing breaks.
Note
Low Risk
Documentation-only; no runtime, auth, or data-path changes until a follow-up implementation PR.
Overview
This PR only adds
cloud-v2/docs/issues/019-developer-api-keys/README.md— a proposal/RFC with no implementation.The doc spells out a planned move away from WorkOS for headless/CI console API keys (create/list/revoke via
workos().apiKeys.*and per-requestcreateValidationinauthenticateApiKeyToken), while keeping WorkOS for interactivementra loginsession JWTs. The intended future shape is aDeveloperOrgApiKeyrecord (hash-only secret storage),msk_<env>_<keyId>_<secret>issuance, andauthenticateMentraApiKeywired intoauthenticateConsoleSessionfor bearer tokens starting withmsk_, with WorkOS keys accepted during a phased cutover.It also captures security (constant-time compare, env pinning, revocation), org resolution (v1 maps to existing
workosOrgIdplumbing), phases 2a–2c, and open questions for review (hash choice, org fields, scopes, legacy key UX).Reviewed by Cursor Bugbot for commit bc678b7. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by cubic
Design-only RFC to replace WorkOS-managed org API keys with Mentra-issued keys for miniapp publishing. Moves issuance and validation into Core + our DB, keeps interactive
mentra loginon WorkOS, and builds on the access gates in PR #3288.New Features
DeveloperOrgApiKeymodel storing onlysha256(secret)plus metadata.msk_<env>_<keyId>_<secret>;keyIdenables indexed lookup and targeted revocation.authenticateConsoleSession: constant‑time compare, throttledlastUsedAt, instantrevokedAt.workosOrgId; per-key scopes can follow later.Migration
workos().apiKeys.*after telemetry shows no WorkOS-key validations.Written for commit bc678b7. Summary will update on new commits.