Skip to content

feat: add auth0 service emulator#89

Open
mvanhorn wants to merge 1 commit intovercel-labs:mainfrom
mvanhorn:feat/auth0-emulator
Open

feat: add auth0 service emulator#89
mvanhorn wants to merge 1 commit intovercel-labs:mainfrom
mvanhorn:feat/auth0-emulator

Conversation

@mvanhorn
Copy link
Copy Markdown
Contributor

@mvanhorn mvanhorn commented Apr 29, 2026

Summary

Adds an Auth0 service emulator with stateful tenant-aware OIDC discovery, Universal Login pages, PKCE auth code flow, refresh token rotation, client credentials, Userinfo, logout, and a Management API for users, roles, applications, organizations, and connections. Mirrors the existing Okta plugin's structure with Auth0-specific surface differences.

Why this matters

Auth0 is one of the two most-used hosted identity providers in the JS ecosystem. The official @auth0/nextjs-auth0 SDK has ~430K weekly npm downloads; @auth0/auth0-react has ~700K weekly. CI tests against Auth0 today either hit production tenants (network-bound, tenant cost, cross-test contamination) or stub at the HTTP level, which loses OIDC flow correctness, refresh token rotation semantics, and per-API audience validation.

emulate's Store and shared OAuth helpers give us a stateful OIDC provider with the same primitives the Okta plugin uses, plus Auth0's distinct surface (tenants, organizations, connections, audience-scoped APIs).

Universal Login

The login page uses the shared core/src/ui.ts design system (terminal green on black, pixel font), so it inherits the same look as the other emulator UIs.

Auth0 Universal Login

Auth0 API Coverage

Endpoint Description
GET /.well-known/openid-configuration OIDC discovery document (tenant-aware)
GET /.well-known/jwks.json JSON Web Key Set
GET /authorize Authorization endpoint with Universal Login + PKCE
POST /oauth/token Token exchange (authorization_code, refresh_token, client_credentials)
GET /userinfo OpenID Connect user info
GET /v2/logout Logout / end session
GET /api/v2/users / POST List and create users
GET /api/v2/roles / POST List and create roles
GET /api/v2/applications / POST List and create applications
GET /api/v2/organizations / POST List and create organizations
GET /api/v2/connections / POST List and create connections

Distinct from Okta

The two providers share the OIDC layer but diverge on:

  • Tenant-aware base URL (<tenant>.auth0.localhost), with a ?tenant=<tenant> query-param fallback for callers that cannot route subdomains in CI
  • Auth0's first-class organizations primitive (org-scoped membership and role assignment)
  • The connections layer (database, social, enterprise) that Auth0 exposes as a configurable login source
  • Per-API audience validation on /authorize, distinct from Okta's authorization-server audiences

Seed config

auth0:
  tenant: my-tenant
  applications:
    - client_id: my-app
      client_secret: secret
      callbacks:
        - http://localhost:3000/api/auth/callback
      grant_types: [authorization_code, refresh_token, client_credentials]
  users:
    - email: dev@example.com
      name: Developer
      password: pass
  roles:
    - name: admin
  connections:
    - name: Username-Password-Authentication
      strategy: auth0
  apis:
    - audience: https://api.example.test/
      name: Example API

Default port

4012 (appended at the end of SERVICE_NAME_LIST after clerk — no other service's port shifts).

Tests

32 Vitest tests covering OIDC discovery, JWKS, PKCE flow, refresh token rotation, client_credentials, userinfo, audience validation, logout, and Management API CRUD across users / roles / applications / organizations / connections.

pnpm --filter @emulators/auth0 test    # 32 passed
pnpm --filter @emulators/auth0 build   # passes
pnpm --filter emulate build            # registry integration verified
pnpm format:check                      # passes
pnpm lint                              # passes

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Apr 29, 2026

@mvanhorn is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

@mvanhorn mvanhorn force-pushed the feat/auth0-emulator branch from 924fcc4 to 7642cc0 Compare April 29, 2026 13:48
@mvanhorn mvanhorn changed the title feat: add Auth0 emulator feat: add auth0 service emulator Apr 29, 2026
app.get("/u/login", renderAuthorize);
app.post("/u/login/callback", handleCallback);
app.get("/u/consent", (c) => {
const client = auth0.applications.findOneBy("client_id", c.req.query("client_id") ?? "");
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.

The consent flow (/u/consent -> /u/consent/callback) always fails with "Unknown user" because user_ref is missing from the hidden form fields passed to the consent page.

Fix on Vercel

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant