feat: add synthetic gateway keys - #27170
Conversation
This stack of pull requests is managed by Graphite. Learn more about stacking. |
|
@codex review |
Dogfood UAT passed for the full three-PR stack. PR1 coverage:
The same preserved database was then migrated through #27171 and #27172 successfully. A full OAuth2 authorization-code refresh was not run manually, but the equivalent active-generation key deletion was exercised deterministically. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dbede83294
ℹ️ 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".
dbede83 to
edea7df
Compare
|
@codex review |
|
Codex Review: Didn't find any major issues. Keep them coming! Reviewed commit: ℹ️ 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". |
ab1009d to
500b588
Compare
|
@codex review |
|
Codex Review: Didn't find any major issues. Hooray! Reviewed commit: ℹ️ 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". |
Final-stack targeted dogfood passed after the FK-decoupling fix.
This supplements the earlier full UI/API/database UAT and validates the final rewritten stack heads. |
johnstcn
left a comment
There was a problem hiding this comment.
Is the additional complexity of the mapping table worth it versus re-using the existing model of one session token per chat?
Provisionerdserver has a similar model but creates a session token per workspace and cleans it up on stop.
98e94a7 to
d7e123e
Compare
|
@codex review |
|
Codex Review: Didn't find any major issues. More of your lovely PRs please. Reviewed commit: ℹ️ 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". |
Resolve the synthetic gateway key by deterministic token name (chatd_<owner_id>_session_token) instead of a mapping table, mirroring the provisionerd session token model. The lookup excludes login_type 'token' rows so a user-created token with the colliding name is never picked up or extended. Near-expiry keys are extended in place under a per-user advisory lock, keeping the key ID stable for in-flight generations. New keys carry a minimal scope as defense in depth.
d7e123e to
fa35022
Compare

Summary
Add a per-user synthetic API key for chatd AI Gateway attribution. Chatd resolves the key from the chat owner, extends it before expiry, and discards the generated bearer token so the key is never a usable credential.
There is no mapping table. The key is resolved from
api_keysby a deterministic token name (chatd_<owner_id>_session_token), mirroring the provisionerd session token model, with three deltas that chatd needs:login_type = 'token'rows, so chatd never picks up (or extends) a real user token. Synthetic keys are minted with the owner's login type, which is nevertoken.expires_atkeeps the key ID stable forever.WHERE login_type = 'token'), so nothing DB-enforces uniqueness for synthetic keys. A per-user advisory lock serializes concurrent mints.Keys carry a minimal scope (
api_key:read) as defense in depth; the delegated gateway path never evaluates scopes and the secret is discarded at mint.Migration 000544 removes the foreign keys from the legacy message and queue
api_key_idcolumns while chatd continues stamping them for rolling compatibility. Stale IDs are tolerated because routing useschats.owner_id. Individual key deletion, delete-all, and password reset remove the key without changing chat history or queue versions, and the next lookup remints it. Suspension does not delete the key; delegated gateway authorization rejects inactive users at request time.This is the first PR in a three-PR rollout and must be fully deployed before #27171.
Refs https://linear.app/codercom/issue/CODAGT-561/maintain-synthetic-api-key-per-user-per-chat