Skip to content

feat(webapp): add multiple environment API key management - #4390

Open
carderne wants to merge 20 commits into
mainfrom
feat/multi-keys-surface
Open

feat(webapp): add multiple environment API key management#4390
carderne wants to merge 20 commits into
mainfrom
feat/multi-keys-surface

Conversation

@carderne

@carderne carderne commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

Projects can create, inspect, expire, and revoke multiple API keys for each environment. Plaintext values are shown only at creation; stored credentials are hashed and the API keys page displays only an obfuscated suffix afterward.

Self-hosted installations support full-access additional keys by default. Authorization extensions can provide additional access presets and optional task selection. Additional keys can also mint scoped public access tokens through the Trigger.dev API without receiving the environment signing key.

Feature notes

  • Only admin+ can create API keys (Developer can make in Development branch).
  • JWT self-signing will be a server call when used with new _ak_ keys.
  • JWTs with long expiry can keep working even with api key deleted (gets priveleges from api key, signed with root key)
  • Unfiltered session listings intentionally preserve the existing broad task-read behavior. Filtered listings enforce task-level scopes for every requested task.
  • Buffered runs without a task identifier are not safely authorizable, so cancel/replay requests fail closed rather than resolving an unscoped run.
  • Batch and waitpoint endpoints intentionally return server-minted, narrowly scoped public tokens to all callers. These tokens have bounded lifetimes and may remain valid until expiry after API-key revocation.

Deployment notes

Deploy the management UI and public-token endpoint with new key creation disabled. Enable creation for selected organizations after the authentication path and released SDK have been verified, then expand availability gradually.

Revoking an API key prevents new bearer requests and new token minting. Public tokens already minted by that key remain valid until their own expiration because they are signed by the environment signing key.

TODO

  • Add "Created by" to the key table
  • Document that streamed batch ingestion is non-atomic and may
    partially accept items before a validation or authorization error.

Follow-ups

  • Add an organization-level feature flag for the API key management UI and creation action.
  • Document rollout ordering: enable additional-key lookup before enabling issuance.
  • Add a system-wide gate that can stop new key issuance without disabling authentication for existing keys.
  • Replace the generic SDK compatibility warning with the first published compatible version. Old SDK will mint an unusable token if given an _ak_ key.
  • Add public documentation covering creation, storage, expiration, revocation, SDK compatibility, and public-token lifetime behavior.
  • Add observability for key creation, revocation, policy preparation failures, and public-token mint failures.
  • Exercise create, copy-once display, authenticate, mint, expire, and revoke flows end to end before broad enablement.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▢️ Resume reviews
  • πŸ” Trigger review

Walkthrough

This PR adds feature-flagged environment API key creation and revocation with RBAC-based presets, task scoping, expiration validation, persistence, telemetry, and audit crumbs. It updates API key listing and management UI with organization scoping, revoked-key filtering, status metadata, and creation or revocation dialogs. It adds public-token minting with scope and expiration validation and JWT signing. Authentication services now accept injectable dependencies. Tests and change notes cover the changes.

πŸš₯ Pre-merge checks | βœ… 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is detailed but omits the template's issue link, checklist, testing steps, changelog, and screenshots sections. Add the required template sections, document the tests that were run, and include screenshots or mark them as not applicable.
Docstring Coverage ⚠️ Warning Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
βœ… Passed checks (3 passed)
Check name Status Explanation
Title check βœ… Passed The title clearly summarizes the primary change: adding management for multiple environment API keys.
Linked Issues check βœ… Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check βœ… Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches πŸ’‘ 1
πŸ“ Generate docstrings πŸ’‘
  • Create stacked PR
  • Commit on current branch
πŸ§ͺ Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/multi-keys-surface

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❀️ Share

Comment @coderabbitai help to get the list of available commands.

@changeset-bot

changeset-bot Bot commented Jul 27, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: d4830db

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@carderne
carderne force-pushed the feat/multi-keys-surface branch from 6aba247 to 2579113 Compare July 27, 2026 11:51
@pkg-pr-new

pkg-pr-new Bot commented Jul 27, 2026

Copy link
Copy Markdown

Open in StackBlitz

@trigger.dev/build

npm i https://pkg.pr.new/@trigger.dev/build@87506ba

trigger.dev

npm i https://pkg.pr.new/trigger.dev@87506ba

@trigger.dev/core

npm i https://pkg.pr.new/@trigger.dev/core@87506ba

@trigger.dev/python

npm i https://pkg.pr.new/@trigger.dev/python@87506ba

@trigger.dev/react-hooks

npm i https://pkg.pr.new/@trigger.dev/react-hooks@87506ba

@trigger.dev/redis-worker

npm i https://pkg.pr.new/@trigger.dev/redis-worker@87506ba

@trigger.dev/rsc

npm i https://pkg.pr.new/@trigger.dev/rsc@87506ba

@trigger.dev/schema-to-json

npm i https://pkg.pr.new/@trigger.dev/schema-to-json@87506ba

@trigger.dev/sdk

npm i https://pkg.pr.new/@trigger.dev/sdk@87506ba

commit: 87506ba

@carderne
carderne force-pushed the feat/multi-keys-surface branch from 2579113 to dbca394 Compare July 27, 2026 12:35
@carderne
carderne force-pushed the feat/multi-keys-surface branch 3 times, most recently from d60d5a5 to ba81e5e Compare July 28, 2026 11:21
@carderne
carderne marked this pull request as ready for review July 29, 2026 17:07
devin-ai-integration[bot]

This comment was marked as resolved.

@carderne
carderne changed the base branch from feat/multi-keys-auth to main July 30, 2026 20:19
@carderne
carderne changed the base branch from main to feat/multi-keys-auth July 30, 2026 20:19
devin-ai-integration[bot]

This comment was marked as resolved.

Base automatically changed from feat/multi-keys-auth to main August 3, 2026 13:00
devin-ai-integration[bot]

This comment was marked as resolved.

@carderne
carderne force-pushed the feat/multi-keys-surface branch from ca744a5 to 5f47b92 Compare August 4, 2026 13:48
devin-ai-integration[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

@carderne
carderne force-pushed the feat/multi-keys-surface branch from c91b01d to b537812 Compare August 5, 2026 17:07
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Observability map

As of d4830db.

18/100 over 412 measured of 428 entry points (base 18, no change)

What this PR changed

route base head now failing
/_app/orgs/:organizationSlug/projects/:projectParam/env/:envParam/apikeys 67 50 error-classification
/api/v1/auth/public-tokens new not measured

FIX FIRST

  • /api/v1/projects/:projectRef/envvars (sensitive) - auth-boundary, request-context
  • /auth/sso (sensitive) - auth-boundary, request-context
  • /_app/orgs/:organizationSlug/settings/team (sensitive) - error-classification, auth-scope, request-context

AUDIT 3 of 50 sensitive mutations record an actor. 47 without one.
CONTEXT 11 of 412 entry points name a tenant on a failure path. 325 appear only here, 39 of them sensitive, in the JSON rather than the fix list.

What the score is made of
CHECKS
  error-classification  167 applicable,  94 pass,   0 sole, global without it 10
  auth-boundary          62 applicable,  57 pass,   0 sole, global without it 15
  auth-scope             19 applicable,  17 pass,   0 sole, global without it 18
  request-context       412 applicable,  11 pass, 223 sole, global without it 64
  audit-trail            50 applicable,   3 pass,   0 sole, not in the score

The score and findings here are report-only and never gate the merge. Separately, a required test suite keeps this tool's symbol and route lists in sync with the code they name, and can fail a pull request that renames or removes a symbol they reference, or that adds the first route with a segment they anticipate. Each failure names the list to edit. The rules and their reasons: internal-packages/observability-map/README.md.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

@trigger-dot-bot

trigger-dot-bot Bot commented Aug 6, 2026

Copy link
Copy Markdown

Preview Deployment

Status Preview Commit Updated
πŸ”΄ Error – d4830db Aug 6, 11:01 UTC

carderne added 17 commits August 6, 2026 09:49
A number passed to `expirationTime` is a Unix timestamp in seconds, not
milliseconds as the JSDoc claimed. Following the old docs produced a token
that effectively never expired.

Also fail loudly when an additional API key reaches a local self-signing
fallback. Those keys are not the environment's JWT signing material, so the
token would never verify. Every endpoint that returns a public access token
sets `x-trigger-jwt`, so this is unreachable today.
The API key policy methods are optional on the plugin-facing controller
contract, so `Pick` over it yields optional members that these call sites
would have to guard. Both already receive the LazyController singleton,
which has substituted its fail-closed defaults, so point them at
HostRbacController and keep the call sites guard-free.
Require both the global issuance switch and organization rollout flag before creating additional keys, while leaving existing credentials available for use and revocation. Show nullable creators and identify SDK v4.5.8 as the first compatible public-token version.
Record bounded outcomes for additional key creation, policy preparation, revocation, and public-token minting.
@carderne
carderne force-pushed the feat/multi-keys-surface branch from 0800403 to 87506ba Compare August 6, 2026 09:41
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

@carderne
carderne force-pushed the feat/multi-keys-surface branch from 4f1ac83 to e8f19ce Compare August 6, 2026 10:21
devin-ai-integration[bot]

This comment was marked as resolved.

@devin-ai-integration devin-ai-integration Bot 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.

Devin Review found 1 new potential issue.

View 1 additional finding in Devin Review.

Open in Devin Review

Comment on lines +140 to +150
where: {
id: environmentId,
organization: { members: { some: { userId } } },
},
select: { id: true, type: true, organizationId: true },
});

if (!environment) {
throw new Error("Environment not found");
}

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.

πŸ” createEnvironmentApiKey only checks org membership, not dev-environment ownership

The environment lookup scopes to organization: { members: { some: { userId } } } only. For a DEVELOPMENT environment (which is per-org-member), any org member's id would satisfy this, so the function on its own would let one member mint a key on another member's dev environment. The single current caller is safe because the route resolves the environment through findEnvironmentBySlug, which restricts DEVELOPMENT to the caller's own orgMember, and then enforces write:apiKeys. Since this is now an exported model function, future callers won't get that protection β€” consider folding the dev-ownership condition into the lookup here.

Open in Devin Review

Was this helpful? React with πŸ‘ or πŸ‘Ž to provide feedback.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant