Skip to content

feat(auth): verifiers on one axis, and a reusable authenticator constructor - #3423

Merged
ben-fornefeld merged 4 commits into
mainfrom
auth-reusable-authenticator-and-jwks-verifier
Jul 27, 2026
Merged

ben-fornefeld merged 4 commits into
mainfrom
auth-reusable-authenticator-and-jwks-verifier

Conversation

@ben-fornefeld

@ben-fornefeld ben-fornefeld commented Jul 27, 2026

Copy link
Copy Markdown
Member

Makes packages/auth usable by a service that authenticates a route before the caller is a user — signup. Today no verifier fits that, so the closest one silently skips OIDC discovery, the issuer cross-check and the iss claim.

Verifiers, now one axis

keys from establishes
JWKSVerifier issuer's JWKS path claims
OIDCVerifier OIDC discovery what the token asserts
LinkedOIDCVerifier OIDC discovery + the internal user

Each adds to the one before. Picking a lower rung is a choice about what you need, never a weaker check — discovery and issuer validation are identical across both OIDC levels.

LinkedOIDCVerifier embeds OIDCVerifier, so linking is additive: the unlinked type has no Verify to call, rather than one that fails at runtime.

Also

  • NewAuthenticator(AuthenticatorConfig[T]) — build an authenticator for a scheme this package doesn't name. Every existing constructor is already a thin literal over commonAuthenticator, but they fix the scheme name and context key, and the type is internal. Named constructors unchanged.
  • iss/sub extraction moved into VerifyIdentity; the resolving path is built on it, so those claims are read in one place.

Breaking

before after
ProviderVerifier LinkedOIDCVerifier
OIDCVerifier (single-issuer) OIDCIssuerVerifier
AdminVerifier JWKSVerifier

Aliases removed rather than deprecated — only belt used them, and it pins by commit. The OIDCVerifier reuse can't break silently: the new one takes a ProviderConfig where the old took a JWTConfig, so callers get a compile error.

NewAdminJWTAuthenticator keeps its name — AdminJWTAuth is a real security scheme.

Verification

Behaviour unchanged for every current caller; dashboard-api verifies exactly as before. New tests cover the identity verifier (reports claims without a lookup, rejects a missing subject, rejects a discovery issuer mismatch), the authenticator constructor (scheme, prefix stripping, 401 on missing header, optional context setter), and that nil verifiers deny rather than panic — the last one panics without its guard, since promotion through an embedded value dereferences before the inner nil check.

No docs/ARCHITECTURE.md change: no service, port, protocol, data store, flow or topology affected.

…KS verifier

Two things a service outside this repo cannot do today without
reimplementing what the package already has.

Every authenticator here is a thin literal over commonAuthenticator, but
the constructors fix both the scheme name and the context key, and the
type is internal. A service defining its own scheme — verifying under a
name of its own, or recording something that is neither a user nor a team
— has to write the header handling and the 401 stamping again. That is
how a scheme ends up subtly different from the others rather than merely
differently named, and it loses the telemetry these emit. NewAuthenticator
takes the parts that vary and keeps the rest.

AdminVerifier verifies a JWT against the issuers in a ProviderConfig and
returns its claims. It resolves no identity and has nothing to do with
admins; admin service tokens were simply its first caller. The name reads
as a restriction that does not exist, which matters because the natural
second caller is anything needing to know a token is validly signed before
knowing who it names. It is IssuerVerifier now, with the old names kept as
deprecated aliases so callers can move in their own time.

dashboard-api moves to the new name in this change; nothing else referred
to it.
@cursor

cursor Bot commented Jul 27, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Auth verification APIs were renamed and split (LinkedOIDCVerifier, OIDCVerifier, JWKSVerifier), so any caller still using ProviderVerifier/AdminVerifier must migrate; runtime behavior for linked OIDC and admin JWT paths is intended to stay equivalent.

Overview
This PR adds a middle tier of OIDC verification that runs full discovery and issuer checks but stops at iss/sub via VerifyIdentity and NewOIDCVerifier, so signup-style flows do not need a fake identity lookup or JWKS-only admin verification. ProviderVerifier becomes LinkedOIDCVerifier; per-issuer NewIdentityVerifier backs the unlinked path while Verify on an identity-only verifier fails if no lookup was configured.

AdminVerifier is removed in favor of JWKSVerifier (same JWKS-path behavior); dashboard-api now calls NewJWKSVerifier. Exported NewAuthenticator/AuthenticatorConfig reuse the shared header extraction, prefix stripping, optional context, and 401 stamping used by the named middleware constructors.

Reviewed by Cursor Bugbot for commit 12b0229. Bugbot is set up for automated code reviews on this repo. Configure here.

@codecov

codecov Bot commented Jul 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM — a clean, backward-compatible refactor with no functional behavior change.

Extended reasoning...

Overview

This PR adds a generic NewAuthenticator(AuthenticatorConfig[T]) constructor to packages/auth for external services that define their own security scheme, and renames AdminVerifier/NewAdminVerifier to IssuerVerifier/NewIssuerVerifier (better reflecting that the verifier resolves no identity). Both changes are additive/aliasing: AdminVerifier, NewAdminVerifier remain as type aliases and deprecated wrapper functions, so no existing caller breaks. dashboard-api/main.go is updated to use the new name; I confirmed via grep that no other file in the repo references the old names outside packages/auth internals, so the rename is safe.

Security risks

None identified. The underlying commonAuthenticator logic (header extraction, prefix handling, 401 stamping, telemetry) is untouched — NewAuthenticator just exposes the existing struct literal fields through a public config struct. The verifier rename is a pure type alias (type IssuerVerifier = token.AdminVerifier), so token.AdminVerifier's JWT/issuer verification behavior is unchanged.

Level of scrutiny

Light-to-moderate is appropriate: this touches the shared auth package, but the change is a mechanical constructor extraction plus a rename via type alias, not new authentication/authorization logic. I built and ran the full test suite for packages/auth locally (all passing) and confirmed no other callers of the old AdminVerifier/NewAdminVerifier names exist that could be affected by the rename.

Other factors

Four new unit tests cover the new constructor's behavior (scheme name/context setter application, prefix stripping, 401 stamping on missing header, optional SetContext). The PR author states go vet/golangci-lint pass and that they compiled an external caller's bootstrap shape against the new export. No architecture doc update was needed since no service responsibility, protocol, or topology changed.

Verification came at two levels and the useful middle one was missing.

ProviderVerifier establishes signature, issuer, subject, and then the
internal user behind them. AdminVerifier establishes only the signature —
and reaches the keys differently, by appending the conventional JWKS path
to the issuer rather than fetching the discovery document, so it never
learns what issuer that document declares and never reads the token's iss
claim.

A caller that must read a subject before that subject is a user — signup,
or anything else creating the identity it authenticates — fits neither.
Reaching for AdminVerifier, as the closest thing available, silently drops
the discovery fetch, the issuer cross-check and the iss claim on the one
route that creates users. Reaching for ProviderVerifier means handing it a
lookup that answers "nobody", which makes not-found a value and turns any
missed check into an authenticated nobody.

NewIdentityVerifier is that middle level: the same discovery and issuer
validation as the resolving verifier, stopping at what the token asserts.
Declining to resolve now weakens nothing about the token. Verify on such a
verifier reports that it has no lookup rather than inventing a zero user,
so the missing capability is unrepresentable rather than merely undocumented.

The iss and sub extraction moves into VerifyIdentity and the resolving path
is built on it, so those claims are read in one place instead of two.

AdminVerifier becomes ServiceTokenVerifier, which is what it is: keys from
a peer's JWKS endpoint, where there is no discovery to do. The earlier name
in this branch, IssuerVerifier, was no better — it hid the same thing.
@ben-fornefeld ben-fornefeld changed the title feat(auth): reusable authenticator constructor, and a name for the JWKS verifier feat(auth): verify a token's identity without resolving it, and a reusable authenticator Jul 27, 2026
…nder them

Nothing in this repo used the deprecated aliases, and belt pins this module
by commit, so there is no caller to give time to. Keeping them would leave
the wrong name reachable and the right one optional.

The internal type follows: it is ServiceTokenVerifier throughout, and the
comments and error strings say so. Leaving them on "admin JWT" would have
left the rename half-done in exactly the places a reader looks when the type
name has already told them otherwise.

Its doc now leads with the property that actually constrains it — keys come
from the issuer's conventional JWKS path, with no discovery document — since
that, not the absent admin semantics, is what makes it the wrong choice for
identity-provider tokens.

NewAdminJWTAuthenticator keeps its name: AdminJWTAuth is a security scheme
that genuinely exists.
ServiceTokenVerifier repeated the mistake it replaced. AdminVerifier named
its first caller; ServiceTokenVerifier named a use case. Neither says what
distinguishes the thing, which is where its keys come from.

The three now sit on one axis and say so:

  JWKSVerifier        keys from the issuer's JWKS path; claims
  OIDCVerifier        keys via OIDC discovery; what the token asserts
  LinkedOIDCVerifier  the above, resolved to an internal user

Adopting those names forced a better shape. IdentityVerifier and
ProviderVerifier were two names bound to one type, with the constructor
deciding which methods worked and Verify failing at runtime when the
verifier had no lookup. Two names for one type is a lie the compiler cannot
catch — and it is worse under these names, since a LinkedOIDCVerifier that
is assignable to an OIDCVerifier and back says the linking is optional.

They are two types now, LinkedOIDCVerifier embedding OIDCVerifier, so
linking is genuinely additive: the unlinked one has no Verify to call
rather than one that reports it cannot. The runtime error is gone because
the state it described is unrepresentable.

Embedding brought its own hazard. A nil verifier is a supported state here
— an unconfigured provider yields one and callers pass it along — but a
promoted method computes the address of the embedded value, dereferencing
the outer pointer before the inner nil check runs. VerifyIdentity is
shadowed to deny rather than panic, with a test that panics without it.

The single-issuer verifier gives up the OIDCVerifier name it held and
becomes OIDCIssuerVerifier, which is what it is.
@ben-fornefeld ben-fornefeld changed the title feat(auth): verify a token's identity without resolving it, and a reusable authenticator feat(auth): verifiers on one axis, and a reusable authenticator constructor Jul 27, 2026
@ben-fornefeld
ben-fornefeld merged commit 923b99b into main Jul 27, 2026
44 checks passed
@ben-fornefeld
ben-fornefeld deleted the auth-reusable-authenticator-and-jwks-verifier branch July 27, 2026 21:12
charlie-e2b added a commit that referenced this pull request Jul 30, 2026
🤖 I have created a release *beep* *boop*
---


## 0.0.1 (2026-07-30)


### Features

* add workspace admin API foundations
([#3314](#3314))
([0f72030](0f72030))
* **api:** LD-gated ClickHouse read switcher
([#3061](#3061))
([29e74ca](29e74ca))
* **api:** soft-delete build layers in DB on user delete
([#3121](#3121))
([ee88776](ee88776))
* **auth:** support admin token team auth
([#2934](#2934))
([5496666](5496666))
* **auth:** verifiers on one axis, and a reusable authenticator
constructor ([#3423](#3423))
([923b99b](923b99b))
* **dashboard-api:** add internal admin route for deleting a user
([#2986](#2986))
([ecc1291](ecc1291))
* **dashboard-api:** add internal team creation
([#2824](#2824))
([375051b](375051b))
* **dashboard-api:** add OIDC admin user bootstrap endpoint
([#2841](#2841))
([6a7a59e](6a7a59e))
* **dashboard-api:** add Ory user profile provider and auth middleware
fix ([#2840](#2840))
([30d40d2](30d40d2))
* **dashboard-api:** add template tags handlers
([#2885](#2885))
([bf52a4b](bf52a4b))
* **dashboard-api:** batch member sync route, and unenumerate
project_type ([#3427](#3427))
([cc16acf](cc16acf))
* **dashboard-api:** expose auth profile admin routes
([#2743](#2743))
([b673a10](b673a10))
* **dashboard-api:** flag sandboxes past data retention
([#3102](#3102))
([9b162bf](9b162bf))
* **dashboard-api:** implement upsertProjectLimits
([#3438](#3438))
([ec1ed29](ec1ed29))
* **dashboard-api:** include build resources in /builds response
([#3009](#3009))
([bf49c32](bf49c32))
* **dashboard-api:** map Ory SSO organizations to E2B teams
([#3094](#3094))
([dbd098f](dbd098f))
* **dashboard-api:** populate Ory identity external_id on admin
bootstrap ([#3062](#3062))
([6c51232](6c51232))
* **dashboard-api:** project upsert, member sync and user purge
([#3442](#3442))
([f997c39](f997c39))
* **dashboard-api:** templates list pagination
([#2904](#2904))
([6882463](6882463))
* **db:** add project_limits, an override the limits owner can write
([#3429](#3429))
([021c2a4](021c2a4))
* improve templates list sorting
([#2983](#2983))
([51ad7ff](51ad7ff))
* **otel:** instrument auth service HTTP client with otelhttp
([#2722](#2722))
([69b085d](69b085d))
* per-team events TTL limit (tier + addons)
([#3181](#3181))
([f76b2cb](f76b2cb))


### Bug Fixes

* added api and orch
([#3454](#3454))
([fda5e45](fda5e45))
* **api:** copy auth/internal into api and dashboard-api image builds
([#3323](#3323))
([bda1fee](bda1fee))
* **api:** invalidate auth cache on API key deletion
([#3324](#3324))
([8b02910](8b02910))
* correct 3 CVES ([#3218](#3218))
([076823b](076823b))
* **dashboard-api:** avoid repeated Ory bootstrap provisioning
([#2940](#2940))
([da5ce59](da5ce59))
* **dashboard-api:** drop removed read-replica accessor in provisioning
tests ([#3340](#3340))
([6addc91](6addc91))
* **dashboard-api:** pass signup metadata to billing provisioning
([#2978](#2978))
([d0ea5b4](d0ea5b4))
* **dashboard-api:** set Ory external_id only after the bootstrap commit
([#3133](#3133))
([00ad04b](00ad04b))
* push client-proxy, dashboard-api, and docker-reverse-proxy image…
([#2953](#2953))
([1d930ee](1d930ee))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: e2b-release-please[bot] <298072688+e2b-release-please[bot]@users.noreply.github.com>
Co-authored-by: Charlie Wyse <charlie.wyse@e2b.dev>
charlie-e2b pushed a commit that referenced this pull request Jul 31, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.1.0](dashboard-api-v0.0.1...dashboard-api-v0.1.0)
(2026-07-31)


### Features

* add workspace admin API foundations
([#3314](#3314))
([0f72030](0f72030))
* **api:** LD-gated ClickHouse read switcher
([#3061](#3061))
([29e74ca](29e74ca))
* **api:** soft-delete build layers in DB on user delete
([#3121](#3121))
([ee88776](ee88776))
* **auth:** support admin token team auth
([#2934](#2934))
([5496666](5496666))
* **auth:** verifiers on one axis, and a reusable authenticator
constructor ([#3423](#3423))
([923b99b](923b99b))
* **dashboard-api:** add internal admin route for deleting a user
([#2986](#2986))
([ecc1291](ecc1291))
* **dashboard-api:** add internal team creation
([#2824](#2824))
([375051b](375051b))
* **dashboard-api:** add OIDC admin user bootstrap endpoint
([#2841](#2841))
([6a7a59e](6a7a59e))
* **dashboard-api:** add Ory user profile provider and auth middleware
fix ([#2840](#2840))
([30d40d2](30d40d2))
* **dashboard-api:** add template tags handlers
([#2885](#2885))
([bf52a4b](bf52a4b))
* **dashboard-api:** batch member sync route, and unenumerate
project_type ([#3427](#3427))
([cc16acf](cc16acf))
* **dashboard-api:** expose auth profile admin routes
([#2743](#2743))
([b673a10](b673a10))
* **dashboard-api:** flag sandboxes past data retention
([#3102](#3102))
([9b162bf](9b162bf))
* **dashboard-api:** implement upsertProjectLimits
([#3438](#3438))
([ec1ed29](ec1ed29))
* **dashboard-api:** include build resources in /builds response
([#3009](#3009))
([bf49c32](bf49c32))
* **dashboard-api:** map Ory SSO organizations to E2B teams
([#3094](#3094))
([dbd098f](dbd098f))
* **dashboard-api:** populate Ory identity external_id on admin
bootstrap ([#3062](#3062))
([6c51232](6c51232))
* **dashboard-api:** project upsert, member sync and user purge
([#3442](#3442))
([f997c39](f997c39))
* **dashboard-api:** templates list pagination
([#2904](#2904))
([6882463](6882463))
* **db:** add project_limits, an override the limits owner can write
([#3429](#3429))
([021c2a4](021c2a4))
* improve templates list sorting
([#2983](#2983))
([51ad7ff](51ad7ff))
* **otel:** instrument auth service HTTP client with otelhttp
([#2722](#2722))
([69b085d](69b085d))
* per-team events TTL limit (tier + addons)
([#3181](#3181))
([f76b2cb](f76b2cb))


### Bug Fixes

* added api and orch
([#3454](#3454))
([fda5e45](fda5e45))
* **api:** copy auth/internal into api and dashboard-api image builds
([#3323](#3323))
([bda1fee](bda1fee))
* **api:** invalidate auth cache on API key deletion
([#3324](#3324))
([8b02910](8b02910))
* correct 3 CVES ([#3218](#3218))
([076823b](076823b))
* creating whitespace to test publish
([#3476](#3476))
([5158cc9](5158cc9))
* **dashboard-api:** avoid repeated Ory bootstrap provisioning
([#2940](#2940))
([da5ce59](da5ce59))
* **dashboard-api:** drop removed read-replica accessor in provisioning
tests ([#3340](#3340))
([6addc91](6addc91))
* **dashboard-api:** pass signup metadata to billing provisioning
([#2978](#2978))
([d0ea5b4](d0ea5b4))
* **dashboard-api:** set Ory external_id only after the bootstrap commit
([#3133](#3133))
([00ad04b](00ad04b))
* push client-proxy, dashboard-api, and docker-reverse-proxy image…
([#2953](#2953))
([1d930ee](1d930ee))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: e2b-release-please[bot] <298072688+e2b-release-please[bot]@users.noreply.github.com>
jakubno pushed a commit that referenced this pull request Aug 3, 2026
…ructor (#3423)

Makes `packages/auth` usable by a service that authenticates a route
**before** the caller is a user — signup. Today no verifier fits that,
so the closest one silently skips OIDC discovery, the issuer cross-check
and the `iss` claim.

## Verifiers, now one axis

| | keys from | establishes |
|---|---|---|
| `JWKSVerifier` | issuer's JWKS path | claims |
| `OIDCVerifier` | OIDC discovery | what the token asserts |
| `LinkedOIDCVerifier` | OIDC discovery | + the internal user |

Each adds to the one before. Picking a lower rung is a choice about what
you need, never a weaker check — discovery and issuer validation are
identical across both OIDC levels.

`LinkedOIDCVerifier` embeds `OIDCVerifier`, so linking is additive: the
unlinked type has no `Verify` to call, rather than one that fails at
runtime.

## Also

- **`NewAuthenticator(AuthenticatorConfig[T])`** — build an
authenticator for a scheme this package doesn't name. Every existing
constructor is already a thin literal over `commonAuthenticator`, but
they fix the scheme name and context key, and the type is `internal`.
Named constructors unchanged.
- **`iss`/`sub` extraction** moved into `VerifyIdentity`; the resolving
path is built on it, so those claims are read in one place.

## Breaking

| before | after |
|---|---|
| `ProviderVerifier` | `LinkedOIDCVerifier` |
| `OIDCVerifier` (single-issuer) | `OIDCIssuerVerifier` |
| `AdminVerifier` | `JWKSVerifier` |

Aliases removed rather than deprecated — only belt used them, and it
pins by commit. The `OIDCVerifier` reuse can't break silently: the new
one takes a `ProviderConfig` where the old took a `JWTConfig`, so
callers get a compile error.

`NewAdminJWTAuthenticator` keeps its name — `AdminJWTAuth` is a real
security scheme.

## Verification

Behaviour unchanged for every current caller; `dashboard-api` verifies
exactly as before. New tests cover the identity verifier (reports claims
without a lookup, rejects a missing subject, rejects a discovery issuer
mismatch), the authenticator constructor (scheme, prefix stripping, 401
on missing header, optional context setter), and that nil verifiers deny
rather than panic — the last one panics without its guard, since
promotion through an embedded value dereferences before the inner nil
check.

No `docs/ARCHITECTURE.md` change: no service, port, protocol, data
store, flow or topology affected.
jakubno pushed a commit that referenced this pull request Aug 3, 2026
🤖 I have created a release *beep* *boop*
---


## 0.0.1 (2026-07-30)


### Features

* add workspace admin API foundations
([#3314](#3314))
([0f72030](0f72030))
* **api:** LD-gated ClickHouse read switcher
([#3061](#3061))
([29e74ca](29e74ca))
* **api:** soft-delete build layers in DB on user delete
([#3121](#3121))
([ee88776](ee88776))
* **auth:** support admin token team auth
([#2934](#2934))
([5496666](5496666))
* **auth:** verifiers on one axis, and a reusable authenticator
constructor ([#3423](#3423))
([f68e713](f68e713))
* **dashboard-api:** add internal admin route for deleting a user
([#2986](#2986))
([ecc1291](ecc1291))
* **dashboard-api:** add internal team creation
([#2824](#2824))
([375051b](375051b))
* **dashboard-api:** add OIDC admin user bootstrap endpoint
([#2841](#2841))
([6a7a59e](6a7a59e))
* **dashboard-api:** add Ory user profile provider and auth middleware
fix ([#2840](#2840))
([30d40d2](30d40d2))
* **dashboard-api:** add template tags handlers
([#2885](#2885))
([bf52a4b](bf52a4b))
* **dashboard-api:** batch member sync route, and unenumerate
project_type ([#3427](#3427))
([6d8dc38](6d8dc38))
* **dashboard-api:** expose auth profile admin routes
([#2743](#2743))
([b673a10](b673a10))
* **dashboard-api:** flag sandboxes past data retention
([#3102](#3102))
([9b162bf](9b162bf))
* **dashboard-api:** implement upsertProjectLimits
([#3438](#3438))
([f4ee390](f4ee390))
* **dashboard-api:** include build resources in /builds response
([#3009](#3009))
([bf49c32](bf49c32))
* **dashboard-api:** map Ory SSO organizations to E2B teams
([#3094](#3094))
([dbd098f](dbd098f))
* **dashboard-api:** populate Ory identity external_id on admin
bootstrap ([#3062](#3062))
([6c51232](6c51232))
* **dashboard-api:** project upsert, member sync and user purge
([#3442](#3442))
([8c90702](8c90702))
* **dashboard-api:** templates list pagination
([#2904](#2904))
([6882463](6882463))
* **db:** add project_limits, an override the limits owner can write
([#3429](#3429))
([5ab6259](5ab6259))
* improve templates list sorting
([#2983](#2983))
([51ad7ff](51ad7ff))
* **otel:** instrument auth service HTTP client with otelhttp
([#2722](#2722))
([69b085d](69b085d))
* per-team events TTL limit (tier + addons)
([#3181](#3181))
([f76b2cb](f76b2cb))


### Bug Fixes

* added api and orch
([#3454](#3454))
([d56e0a8](d56e0a8))
* **api:** copy auth/internal into api and dashboard-api image builds
([#3323](#3323))
([bda1fee](bda1fee))
* **api:** invalidate auth cache on API key deletion
([#3324](#3324))
([8b02910](8b02910))
* correct 3 CVES ([#3218](#3218))
([076823b](076823b))
* **dashboard-api:** avoid repeated Ory bootstrap provisioning
([#2940](#2940))
([da5ce59](da5ce59))
* **dashboard-api:** drop removed read-replica accessor in provisioning
tests ([#3340](#3340))
([6addc91](6addc91))
* **dashboard-api:** pass signup metadata to billing provisioning
([#2978](#2978))
([d0ea5b4](d0ea5b4))
* **dashboard-api:** set Ory external_id only after the bootstrap commit
([#3133](#3133))
([00ad04b](00ad04b))
* push client-proxy, dashboard-api, and docker-reverse-proxy image…
([#2953](#2953))
([1d930ee](1d930ee))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: e2b-release-please[bot] <298072688+e2b-release-please[bot]@users.noreply.github.com>
Co-authored-by: Charlie Wyse <charlie.wyse@e2b.dev>
jakubno pushed a commit that referenced this pull request Aug 3, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.1.0](dashboard-api-v0.0.1...dashboard-api-v0.1.0)
(2026-07-31)


### Features

* add workspace admin API foundations
([#3314](#3314))
([0f72030](0f72030))
* **api:** LD-gated ClickHouse read switcher
([#3061](#3061))
([29e74ca](29e74ca))
* **api:** soft-delete build layers in DB on user delete
([#3121](#3121))
([ee88776](ee88776))
* **auth:** support admin token team auth
([#2934](#2934))
([5496666](5496666))
* **auth:** verifiers on one axis, and a reusable authenticator
constructor ([#3423](#3423))
([f68e713](f68e713))
* **dashboard-api:** add internal admin route for deleting a user
([#2986](#2986))
([ecc1291](ecc1291))
* **dashboard-api:** add internal team creation
([#2824](#2824))
([375051b](375051b))
* **dashboard-api:** add OIDC admin user bootstrap endpoint
([#2841](#2841))
([6a7a59e](6a7a59e))
* **dashboard-api:** add Ory user profile provider and auth middleware
fix ([#2840](#2840))
([30d40d2](30d40d2))
* **dashboard-api:** add template tags handlers
([#2885](#2885))
([bf52a4b](bf52a4b))
* **dashboard-api:** batch member sync route, and unenumerate
project_type ([#3427](#3427))
([6d8dc38](6d8dc38))
* **dashboard-api:** expose auth profile admin routes
([#2743](#2743))
([b673a10](b673a10))
* **dashboard-api:** flag sandboxes past data retention
([#3102](#3102))
([9b162bf](9b162bf))
* **dashboard-api:** implement upsertProjectLimits
([#3438](#3438))
([f4ee390](f4ee390))
* **dashboard-api:** include build resources in /builds response
([#3009](#3009))
([bf49c32](bf49c32))
* **dashboard-api:** map Ory SSO organizations to E2B teams
([#3094](#3094))
([dbd098f](dbd098f))
* **dashboard-api:** populate Ory identity external_id on admin
bootstrap ([#3062](#3062))
([6c51232](6c51232))
* **dashboard-api:** project upsert, member sync and user purge
([#3442](#3442))
([8c90702](8c90702))
* **dashboard-api:** templates list pagination
([#2904](#2904))
([6882463](6882463))
* **db:** add project_limits, an override the limits owner can write
([#3429](#3429))
([5ab6259](5ab6259))
* improve templates list sorting
([#2983](#2983))
([51ad7ff](51ad7ff))
* **otel:** instrument auth service HTTP client with otelhttp
([#2722](#2722))
([69b085d](69b085d))
* per-team events TTL limit (tier + addons)
([#3181](#3181))
([f76b2cb](f76b2cb))


### Bug Fixes

* added api and orch
([#3454](#3454))
([d56e0a8](d56e0a8))
* **api:** copy auth/internal into api and dashboard-api image builds
([#3323](#3323))
([bda1fee](bda1fee))
* **api:** invalidate auth cache on API key deletion
([#3324](#3324))
([8b02910](8b02910))
* correct 3 CVES ([#3218](#3218))
([076823b](076823b))
* creating whitespace to test publish
([#3476](#3476))
([6b4177f](6b4177f))
* **dashboard-api:** avoid repeated Ory bootstrap provisioning
([#2940](#2940))
([da5ce59](da5ce59))
* **dashboard-api:** drop removed read-replica accessor in provisioning
tests ([#3340](#3340))
([6addc91](6addc91))
* **dashboard-api:** pass signup metadata to billing provisioning
([#2978](#2978))
([d0ea5b4](d0ea5b4))
* **dashboard-api:** set Ory external_id only after the bootstrap commit
([#3133](#3133))
([00ad04b](00ad04b))
* push client-proxy, dashboard-api, and docker-reverse-proxy image…
([#2953](#2953))
([1d930ee](1d930ee))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: e2b-release-please[bot] <298072688+e2b-release-please[bot]@users.noreply.github.com>
chill-czar pushed a commit to chill-czar/infra that referenced this pull request Aug 4, 2026
…ructor (e2b-dev#3423)

Makes `packages/auth` usable by a service that authenticates a route
**before** the caller is a user — signup. Today no verifier fits that,
so the closest one silently skips OIDC discovery, the issuer cross-check
and the `iss` claim.

## Verifiers, now one axis

| | keys from | establishes |
|---|---|---|
| `JWKSVerifier` | issuer's JWKS path | claims |
| `OIDCVerifier` | OIDC discovery | what the token asserts |
| `LinkedOIDCVerifier` | OIDC discovery | + the internal user |

Each adds to the one before. Picking a lower rung is a choice about what
you need, never a weaker check — discovery and issuer validation are
identical across both OIDC levels.

`LinkedOIDCVerifier` embeds `OIDCVerifier`, so linking is additive: the
unlinked type has no `Verify` to call, rather than one that fails at
runtime.

## Also

- **`NewAuthenticator(AuthenticatorConfig[T])`** — build an
authenticator for a scheme this package doesn't name. Every existing
constructor is already a thin literal over `commonAuthenticator`, but
they fix the scheme name and context key, and the type is `internal`.
Named constructors unchanged.
- **`iss`/`sub` extraction** moved into `VerifyIdentity`; the resolving
path is built on it, so those claims are read in one place.

## Breaking

| before | after |
|---|---|
| `ProviderVerifier` | `LinkedOIDCVerifier` |
| `OIDCVerifier` (single-issuer) | `OIDCIssuerVerifier` |
| `AdminVerifier` | `JWKSVerifier` |

Aliases removed rather than deprecated — only belt used them, and it
pins by commit. The `OIDCVerifier` reuse can't break silently: the new
one takes a `ProviderConfig` where the old took a `JWTConfig`, so
callers get a compile error.

`NewAdminJWTAuthenticator` keeps its name — `AdminJWTAuth` is a real
security scheme.

## Verification

Behaviour unchanged for every current caller; `dashboard-api` verifies
exactly as before. New tests cover the identity verifier (reports claims
without a lookup, rejects a missing subject, rejects a discovery issuer
mismatch), the authenticator constructor (scheme, prefix stripping, 401
on missing header, optional context setter), and that nil verifiers deny
rather than panic — the last one panics without its guard, since
promotion through an embedded value dereferences before the inner nil
check.

No `docs/ARCHITECTURE.md` change: no service, port, protocol, data
store, flow or topology affected.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants