feat: full WorkOS API emulator (emulate, dev, RBAC, webhooks, events, 84% API coverage)#100
Merged
feat: full WorkOS API emulator (emulate, dev, RBAC, webhooks, events, 84% API coverage)#100
Conversation
Port the WorkOS emulator from vercel-labs/emulate into the CLI as a
`workos emulate` command with a `workos/emulate` programmatic API.
Core infrastructure (store, ID generation, cursor pagination, JWT,
Hono server factory, auth/error middleware) lives in src/emulate/core/.
WorkOS-specific plugin (12 route files covering organizations, users,
memberships, connections, SSO, auth flows) lives in src/emulate/workos/.
The emulator supports:
- CLI: `workos emulate --port 4100 --seed config.yaml --json`
- Programmatic: `createEmulator({ port: 0, seed: { users: [...] } })`
- Health check at /health
- Seed config via YAML/JSON (auto-detected or explicit path)
- Store reset for test isolation
- Random port assignment (port: 0) for parallel test suites
New dependencies: hono, @hono/node-server, jose
Developer tool that reads a WorkOS OpenAPI spec (YAML/JSON) and generates TypeScript entity types, store registrations, formatter helpers, and route stubs matching the hand-written emulate patterns. Includes 46 unit tests covering parsing, code generation, and idempotency.
Document workos emulate, workos dev, seed configuration, programmatic API, and emulated endpoint coverage.
authkit-nextjs (and the @workos-inc/node SDK) read WORKOS_API_HOSTNAME, WORKOS_API_PORT, and WORKOS_API_HTTPS — not WORKOS_API_BASE_URL. buildDevEnv now sets both styles so the emulator works with authkit SDKs and direct consumers.
workos dev now seeds a default user (test@example.com / password) and organization so the AuthKit login flow works out of the box. The banner prints the credentials for easy copy-paste. Skipped when the user provides --seed or a workos-emulate.config.* file is auto-detected in the project directory.
…redirects) - Expose apiKey on Emulator interface; use it in dev/emulate CLI output and buildDevEnv() so custom seed apiKeys propagate correctly - Update JWT issuer to actual bound URL after port resolution, fixing iss mismatch when using port: 0 - Clean up password resets, email verifications, and magic auths on user deletion; harden password_reset/confirm to return 404 if user was deleted - Restrict redirect_uri in authorize endpoints to localhost origins, preventing open-redirect abuse - Remove unused jose dependency
Add token refresh with rotation, logout redirects, multi-user authorize (login_hint), impersonation, sealed sessions (AES-256-GCM), MFA challenge/verify, device authorization, and AuthKit OAuth complete flow. New grant types: refresh_token, mfa-totp, organization-selection, device_code. Includes shared entity/store/helper infrastructure for all 4 API parity phases.
Add invitations CRUD (create/accept/revoke/resend/by-token), config endpoints (redirect URIs, CORS origins, JWT template), user features (authorized apps, connected accounts, data providers), and widget token generation.
Add environment roles, org roles with priority ordering, permissions CRUD, role-permission management, authorization resources, permission checks, and role assignments. JWT tokens now include role and permissions claims for org-scoped sessions.
…gs, and more Add 9 CRUD domains: Directory Sync, Audit Logs, Feature Flags, Connect, Data Integrations, Radar, API Keys, Portal, and Legacy MFA. Each domain follows the entity/store/helper/route pattern with full test coverage.
…ok delivery Add cross-cutting event system with webhook delivery. Collection-level hooks (Option A) auto-emit events on insert/update/delete for all major entities. Hybrid route-level emission for action-specific events (invitation accept/revoke, authentication succeeded). Webhook endpoints CRUD with HMAC-SHA256 signed delivery (fire-and-forget, 5s timeout). Events API with paginated listing and type filtering. Review: 2 cycles (6 findings in cycle 1, all resolved in cycle 2).
Remove unused variables and imports flagged by oxlint: - sessions.spec.ts: remove unused `req` helper and `headers` constant - auth.spec.ts: remove unused `user` variable in impersonator test - data-integrations.spec.ts: remove unused `getWorkOSStore` import and `store` variable - event-bus.spec.ts: use non-null assertion instead of optional chaining
Compares the WorkOS OpenAPI spec against emulator route registrations to report missing endpoints, extra endpoints, and coverage percentage. Usage: pnpm check:coverage ~/Developer/workos/packages/api/open-api-spec.yaml
…ation The refresh token handler now reads organization_id from the request body, falling back to the stored token's org. This enables the SDK's switchToOrganization flow during token refresh.
The AuthKit SDK sends refresh_token grants to /x/authkit/users/authenticate rather than /user_management/authenticate. Register the same handler on both paths so the SDK's refreshTokens() and switchToOrganization() work against the emulator.
2b47266 to
3494dde
Compare
workos emulate, workos dev, pipes, codegen)Add all new endpoint groups from auth completeness, user management, authorization, CRUD domains, and events/webhooks phases. Add seed config examples for roles, permissions, and webhook endpoints.
This was referenced Mar 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a full local WorkOS API emulator to the CLI, enabling developers to test WorkOS integrations without hitting the live API. Covers ~84% of the OpenAPI spec surface.
Three runtime contexts:
workos emulate— standalone server for CI/ephemeral useworkos dev— process orchestrator (emulator + your app in one command)import { createEmulator } from 'workos/emulate'for test suitesWhat's included
Core infrastructure (
src/emulate/core/)Phase 1: Auth Completeness
/x/authkit/users/authenticatealias for SDK compatibilityPhase 2: User Management
Phase 3: Authorization (RBAC + FGA)
roleandpermissionsclaims for org-scoped sessionsPhase 4: CRUD Domains (9 domains)
Phase 5: Events & Webhooks
Developer tools
pnpm gen:routes <openapi-spec>— codegen script for scaffolding new routespnpm check:coverage <openapi-spec>— coverage checker comparing emulator vs OpenAPI specTest plan
pnpm buildpassespnpm testpasses (1509 tests)pnpm typecheckpassespnpm lintpasses (0 warnings)pnpm check:coveragereports 84% coverage against OpenAPI specauthenticateWithRefreshTokenworkos devwith AuthKit client page