Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
dde68a3
feat: add `workos emulate` command and programmatic emulator API
nicknisi Mar 24, 2026
54d9a11
feat: add workos dev command for local development with emulator
nicknisi Mar 24, 2026
536efda
feat: add pipes emulation routes for user/provider connections
nicknisi Mar 24, 2026
658326b
feat: add gen:routes codegen script for emulator route generation
nicknisi Mar 24, 2026
e061635
chore: formatting:
nicknisi Mar 24, 2026
5a32fc3
docs: add local development section to README
nicknisi Mar 24, 2026
5cb0846
fix: set decomposed SDK env vars in workos dev
nicknisi Mar 24, 2026
f6c38f9
feat: seed default test user in workos dev
nicknisi Mar 24, 2026
dd21d7d
chore: formatting:
nicknisi Mar 25, 2026
d0d0097
fix: address emulator review findings (API key, JWT issuer, cleanup, …
nicknisi Mar 25, 2026
2ebbbf0
feat: emulator auth completeness + shared entity infrastructure
nicknisi Mar 25, 2026
d582377
feat: emulator user management — invitations, config, widgets
nicknisi Mar 25, 2026
cc24d88
feat: emulator authorization — RBAC roles, permissions, FGA resources
nicknisi Mar 25, 2026
b7e50a8
feat: emulator CRUD domains — directory sync, audit logs, feature fla…
nicknisi Mar 25, 2026
8fd6b17
feat: emulator events & webhooks — event bus, collection hooks, webho…
nicknisi Mar 25, 2026
1687d3e
chore: formatting:
nicknisi Mar 25, 2026
430640d
fix: resolve lint warnings in emulator spec files
nicknisi Mar 25, 2026
6b8a544
feat: add emulator API coverage checker script
nicknisi Mar 25, 2026
fc31073
fix: allow organization_id in refresh_token grant for switchToOrganiz…
nicknisi Mar 25, 2026
3494dde
fix: alias /x/authkit/users/authenticate for SDK refresh token flow
nicknisi Mar 25, 2026
af1a848
chore: update README
nicknisi Mar 26, 2026
76024f0
docs: update README emulated endpoints table for phases 1-5
nicknisi Mar 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 163 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ Resource Management:
api-key Manage per-org API keys
org-domain Manage organization domains

Local Development:
emulate Start a local WorkOS API emulator
dev Start emulator + your app in one command

Workflows:
seed Declarative resource provisioning from YAML
setup-org One-shot organization onboarding
Expand Down Expand Up @@ -192,6 +196,158 @@ Inspects a directory's sync state, user/group counts, recent events, and detects
workos debug-sync directory_01ABC123
```

### Local Development

Test your WorkOS integration locally without hitting the live API. The emulator provides a full in-memory WorkOS API replacement with all major endpoints.

#### `workos dev` — One command to start everything

The fastest way to develop locally. Starts the emulator and your app together, auto-detecting your framework and injecting the right environment variables.

```bash
# Auto-detects framework (Next.js, Vite, Remix, SvelteKit, etc.) and dev command
workos dev

# Override the dev command
workos dev -- npx vite --port 5173

# Custom emulator port and seed data
workos dev --port 8080 --seed workos-emulate.config.yaml
```

Your app receives these environment variables automatically:

- `WORKOS_API_BASE_URL` — points to the local emulator (e.g. `http://localhost:4100`)
- `WORKOS_API_KEY` — `sk_test_default`
- `WORKOS_CLIENT_ID` — `client_emulate`

#### `workos emulate` — Standalone emulator

Run the emulator on its own for CI, test suites, or when you want manual control.

```bash
# Start with defaults (port 4100)
workos emulate

# CI-friendly: JSON output, custom port
workos emulate --port 9100 --json
# → {"url":"http://localhost:9100","port":9100,"apiKey":"sk_test_default","health":"http://localhost:9100/health"}

# Pre-load seed data
workos emulate --seed workos-emulate.config.yaml
```

The emulator supports `GET /health` for readiness polling and shuts down cleanly on Ctrl+C.

#### Seed configuration

Create a `workos-emulate.config.yaml` (auto-detected) or pass `--seed <path>`:

```yaml
users:
- email: alice@acme.com
first_name: Alice
password: test123
email_verified: true

organizations:
- name: Acme Corp
domains:
- domain: acme.com
state: verified
memberships:
- user_id: <user_id>
role: admin

connections:
- name: Acme SSO
organization: Acme Corp
connection_type: GenericSAML
domains: [acme.com]

roles:
- slug: admin
name: Admin
permissions: [posts:read, posts:write]

permissions:
- slug: posts:read
name: Read Posts
- slug: posts:write
name: Write Posts

webhookEndpoints:
- url: http://localhost:3000/webhooks
events: [user.created, organization.updated]
```

#### Programmatic API

Use the emulator directly in test suites without the CLI:

```typescript
import { createEmulator } from 'workos/emulate';

const emulator = await createEmulator({
port: 0, // random available port
seed: {
users: [{ email: 'test@example.com', password: 'secret' }],
},
});

// Use emulator.url as your WORKOS_API_BASE_URL
const res = await fetch(`${emulator.url}/user_management/users`, {
headers: { Authorization: 'Bearer sk_test_default' },
});

// Reset between tests (clears data, re-applies seed)
emulator.reset();

// Clean up
await emulator.close();
```

#### Emulated endpoints

The emulator covers the full WorkOS API surface (~84% of OpenAPI spec endpoints). Run `pnpm check:coverage <openapi-spec>` to see exact coverage.

| Endpoint Group | Routes |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Organizations | CRUD, external_id lookup, domain management |
| Users | CRUD, email uniqueness, password management |
| Organization memberships | CRUD, role assignment, deactivate/reactivate |
| Organization domains | CRUD, verification |
| SSO connections | CRUD, domain-based lookup |
| SSO flow | Authorize, token exchange, profile, JWKS, SSO logout |
| AuthKit | OAuth authorize (login_hint, multi-user), authenticate (7 grant types incl. refresh_token, MFA TOTP, org selection, device code), PKCE, sealed sessions, impersonation |
| Sessions | List, revoke, logout redirect, JWKS per client |
| Email verification | Send code, confirm |
| Password reset | Create token, confirm |
| Magic auth | Create code |
| Auth factors | TOTP enrollment, delete |
| MFA challenges | Create challenge, verify code |
| Invitations | CRUD, accept, revoke, resend, get by token |
| Config | Redirect URIs, CORS origins, JWT template |
| User features | Authorized apps, connected accounts, data providers |
| Widgets | Token generation |
| Authorization (RBAC) | Environment roles, org roles (priority ordering), permissions, role-permission management |
| Authorization (FGA) | Resources CRUD, permission checks, role assignments |
| Directory Sync | List/get/delete directories, users, groups |
| Audit Logs | Actions, schemas, events, exports, org config/retention |
| Feature Flags | List/get, enable/disable, targets, org/user evaluations |
| Connect | Applications CRUD, client secrets |
| Data Integrations | OAuth authorize + token exchange |
| Radar | Attempts list/get, allow/deny lists |
| API Keys | Validate, delete, list by org |
| Portal | Generate admin portal links |
| Legacy MFA | Enroll/get/delete factors, challenge/verify |
| Webhook Endpoints | CRUD with auto-generated secrets, secret masking |
| Events | Paginated event stream with type filtering |
| Event Bus | Auto-emits events on entity CRUD via collection hooks, fire-and-forget webhook delivery with HMAC signatures |
| Pipes | Connection CRUD, mock `getAccessToken()` |

JWT tokens include `role` and `permissions` claims for org-scoped sessions. All list endpoints support cursor pagination (`before`, `after`, `limit`, `order`). Error responses match the WorkOS format (`{ message, code, errors }`).

### Environment Management

```bash
Expand Down Expand Up @@ -466,12 +622,13 @@ workos install --api-key sk_test_xxx --client-id client_xxx --no-commit 2>/dev/n

### Environment Variables

| Variable | Effect |
| ------------------------ | -------------------------------------------------------- |
| `WORKOS_API_KEY` | API key for management commands (bypasses stored config) |
| `WORKOS_NO_PROMPT=1` | Force non-interactive mode + JSON output |
| `WORKOS_FORCE_TTY=1` | Force interactive mode even when piped |
| `WORKOS_TELEMETRY=false` | Disable telemetry |
| Variable | Effect |
| ------------------------ | --------------------------------------------------------- |
| `WORKOS_API_KEY` | API key for management commands (bypasses stored config) |
| `WORKOS_API_BASE_URL` | Override API base URL (set automatically by `workos dev`) |
| `WORKOS_NO_PROMPT=1` | Force non-interactive mode + JSON output |
| `WORKOS_FORCE_TTY=1` | Force interactive mode even when piped |
| `WORKOS_TELEMETRY=false` | Disable telemetry |

### Command Discovery

Expand Down
16 changes: 15 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@
"typescript": {
"definition": "dist/index.d.ts"
},
"exports": {
".": {
"import": "./dist/index.js",
"types": "./dist/index.d.ts"
},
"./emulate": {
"import": "./dist/emulate/index.js",
"types": "./dist/emulate/index.d.ts"
}
},
"dependencies": {
"@anthropic-ai/claude-agent-sdk": "~0.2.62",
"@anthropic-ai/sdk": "^0.78.0",
Expand All @@ -51,6 +61,8 @@
"semver": "^7.7.4",
"uuid": "^13.0.0",
"xstate": "^5.28.0",
"hono": "^4",
"@hono/node-server": "^1",
"yaml": "^2.8.2",
"yargs": "^18.0.0",
"zod": "^4.3.6"
Expand Down Expand Up @@ -96,7 +108,9 @@
"eval:diff": "tsx tests/evals/index.ts diff",
"eval:prune": "tsx tests/evals/index.ts prune",
"eval:logs": "tsx tests/evals/index.ts logs",
"eval:show": "tsx tests/evals/index.ts show"
"eval:show": "tsx tests/evals/index.ts show",
"gen:routes": "tsx scripts/gen-routes.ts",
"check:coverage": "tsx scripts/check-coverage.ts"
},
"author": "WorkOS",
"license": "MIT"
Expand Down
6 changes: 6 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading