SIGN IN SIGN UP

Release v8.0.0: Universal Runtime Support & API Modernization (#1370)

## Overview

Version 8 is a major release focused on **universal runtime
compatibility**, **PKCE authentication support**, and **API
modernization**. The SDK now works seamlessly across Node.js, Deno, Bun,
and Cloudflare Workers while removing long-deprecated APIs.

---

## BREAKING CHANGES

### Runtime & Build System

**1. Node.js Version Requirement** (BREAKING)
- **Changed:** Minimum Node.js version: `16` → `20`
- **Reason:** Node 18 reached end-of-life in April 2025
- **Files:** `package.json` (`engines.node`)
- **Migration:** Update to Node.js 20 or higher

**2. Package Type Change to ESM-First** (BREAKING)
- **Changed:** `package.json` now includes `"type": "module"`
- **Impact:** The package is now ESM-first with dual CJS/ESM exports
- **Files:** `package.json`
- **Migration:** Most users won't need changes due to conditional
exports, but projects with custom build configurations may need
adjustments

**3. Build System Migration** (Internal)
- **Changed:** Migrated from `tsc` to `tsdown` (Rolldown/Oxc-based) for
building
- **Added:** `tsdown.config.ts` with dual-config approach:
- **ESM build:** Unbundled with external dependencies (optimal for
tree-shaking)
- **CJS build:** Bundles ESM-only dependencies (`iron-webcrypto`,
`uint8array-extras`) for compatibility
- **Impact:** Faster builds, lower memory usage, improved tree-shaking,
better compatibility with various bundlers and package managers

### Removed Internal Classes (BREAKING)

**4. HTTP Client Removal** (BREAKING)
- **Removed:** `NodeHttpClient` class and `createHttpClient()` method
- **Files:** `src/common/net/node-client.ts` (deleted)
- **Impact:** Only affects deep imports into internal modules (never
part of public API)
- **Migration:** Use `WorkOS` instance instead - HTTP is handled
automatically

**5. Crypto Provider Removal** (BREAKING)
- **Removed:** `NodeCryptoProvider`, `IronSessionProvider`,
`EdgeIronSessionProvider`, `WebIronSessionProvider`
- **Changed:** Now using `iron-webcrypto` v2 directly with lightweight
wrapper
- **Files:** `src/common/crypto/node-crypto-provider.ts` (deleted),
`src/common/iron-session/*` (deleted), `src/common/crypto/seal.ts`
(added)
- **Impact:** Only affects deep imports into internal modules
- **Migration:** Use `WorkOS` instance methods - crypto is handled
automatically

### Directory Sync (BREAKING)

**6. DirectoryUser Interface Changes** (BREAKING)
- **Removed fields:**
  - `emails` → Use `customAttributes.emails`
  - `username` → Use `customAttributes.username`
  - `jobTitle` → Use `customAttributes.jobTitle`
- **Removed utility:** `getPrimaryEmail()` function
- **Files:**
`src/directory-sync/interfaces/directory-user.interface.ts`,
`src/directory-sync/utils/get-primary-email.ts` (deleted)
- **Migration:**
  ```typescript
  // v7
  user.emails
  user.username
  user.jobTitle

  // v8
  user.customAttributes?.emails
  user.customAttributes?.username
  user.customAttributes?.jobTitle
  ```

### User Management (BREAKING)

**7. AuthorizationURLOptions Changes** (BREAKING)
- **Removed:** `context` field (no longer supported)
- **Files:**
`src/user-management/interfaces/authorization-url-options.interface.ts`
- **Migration:** Remove the `context` parameter from authorization URL
calls

**8. Removed Deprecated Methods** (BREAKING)
- **Removed:**
  - `sendMagicAuthCode()` → Use `userManagement.sendMagicCode()` instead
- `sendPasswordResetEmail()` → Use
`userManagement.sendPasswordResetEmail()` instead
- `refreshAndSealSessionData()` → Use new session helper methods instead
- **Files:** `src/user-management/user-management.ts`, serializers
removed

**9. listOrganizationMemberships Requires userId or organizationId**
(BREAKING)
- **Changed:** `listOrganizationMemberships()` now requires either
`userId` or `organizationId`
- **Files:** `src/user-management/user-management.ts`
- **Migration:**
  ```typescript
  // v7 - Could call without parameters
  workos.userManagement.listOrganizationMemberships();

  // v8 - Must specify userId or organizationId
workos.userManagement.listOrganizationMemberships({ userId: 'user_123'
});
  // OR
workos.userManagement.listOrganizationMemberships({ organizationId:
'org_456' });
  ```

### SSO (BREAKING)

**10. SSOAuthorizationURLOptions Type Changes** (BREAKING)
- **Changed:** Converted to discriminated union for type safety
- **Removed:** `domain` field (deprecated)
- **Files:** `src/sso/interfaces/authorization-url-options.interface.ts`
- **Impact:** Stricter TypeScript types - must now specify exactly one
of: `connection`, `organization`, or `provider`
- **Migration:**
  ```typescript
  // v7 - Multiple options allowed
  { connection: 'conn_123', organization: 'org_456' } // Both accepted

  // v8 - Mutually exclusive (enforced by types)
  { connection: 'conn_123' } // OR
  { organization: 'org_456' } // OR
  { provider: 'GoogleOAuth' }
  ```

**11. Connection Interface** (BREAKING)
- **Removed:** Several deprecated internal fields
- **Files:** `src/sso/interfaces/connection.interface.ts`
- **Migration:** Use only documented fields

### MFA (BREAKING)

**12. Method Removal** (BREAKING)
- **Removed:** `verifyFactor()` method
- **Files:** `src/mfa/mfa.ts`,
`src/mfa/interfaces/verify-factor-options.ts` (deleted)
- **Migration:** Use `verifyChallenge()` instead (same functionality)
  ```typescript
  // v7
  await workos.mfa.verifyFactor({ authenticationFactorId, code });

  // v8
  await workos.mfa.verifyChallenge({ authenticationFactorId, code });
  ```

### Organizations (BREAKING)

**13. Organization Options Changes** (BREAKING)
- **Removed from CreateOrganizationOptions and
UpdateOrganizationOptions:**
  - `allowProfilesOutsideOrganization`
  - `domains` (use `domainData` instead)
- **Files:** `src/organizations/interfaces/*.interface.ts`
- **Migration:** Remove these fields from organization creation/update
calls

**14. Organization Domain Enum** (BREAKING)
- **Removed:** `LegacyVerified` from `OrganizationDomainState` enum
- **Files:**
`src/organizations/interfaces/organization-domain.interface.ts`
- **Migration:** Use `Verified` instead

### Events (BREAKING)

**15. Event Type Removals** (BREAKING)
- **Removed event interfaces:**
  - `DsyncDeactivatedEvent` → Use `dsync.deleted` instead
  - `OrganizationMembershipAdded` → Not applicable in v8
  - `OrganizationMembershipRemoved` → Not applicable in v8
- **Files:** `src/common/interfaces/event.interface.ts`
- **Migration:**
  ```typescript
  // v7
  if (event.event === 'dsync.deactivated') { }

  // v8
  if (event.event === 'dsync.deleted') { }
  ```

### Vault (BREAKING)

**16. Removed Deprecated Method Aliases** (BREAKING)
- **Removed methods:**
  - `createSecret()` → Use `createObject()` instead
  - `listSecrets()` → Use `listObjects()` instead
  - `listSecretVersions()` → Use `listObjectVersions()` instead
  - `readSecret()` → Use `readObject()` instead
  - `describeSecret()` → Use `describeObject()` instead
  - `updateSecret()` → Use `updateObject()` instead
  - `deleteSecret()` → Use `deleteObject()` instead
- **Files:** `src/vault/vault.ts`
- **Migration:** Replace all `*Secret` methods with `*Object`
equivalents

### Webhooks (NON-BREAKING)

**17. constructEvent Payload Typing** (NON-BREAKING)
- **Changed:** `constructEvent` payload parameter typed as
`Record<string, unknown>` for better type safety
- **Files:** `src/webhooks/webhooks.ts`
- **Impact:** Stricter typing, but backwards compatible

---

## NEW FEATURES

**18. PKCE Authentication Support** (NON-BREAKING)
- **Added:** Full PKCE (Proof Key for Code Exchange) support for public
and confidential clients
- **API key now optional:** Initialize with just `clientId` for
PKCE-only mode
- **New methods:**
- `userManagement.getAuthorizationUrlWithPKCE()` - generates PKCE
internally, returns `{ url, state, codeVerifier }`
- `userManagement.authenticateWithCodeAndVerifier()` - explicit PKCE
token exchange
  - `workos.pkce.generate()` - manual PKCE generation
- **Enhanced:** `authenticateWithCode()` auto-detects client mode based
on credentials
- **Example:**
  ```typescript
  import { WorkOS } from '@workos-inc/node';

  // Public client (no API key)
  const workos = new WorkOS({ clientId: 'client_123' });

  // Generate authorization URL with PKCE
const { url, state, codeVerifier } = await
workos.userManagement.getAuthorizationUrlWithPKCE({
    redirectUri: 'myapp://callback',
    provider: 'authkit',
  });

  // Exchange code for tokens
const { accessToken, refreshToken, user } = await
workos.userManagement.authenticateWithCode({
    code: authCode,
    codeVerifier,
  });
  ```

**19. createWorkOS Factory Function** (NON-BREAKING)
- **Added:** `createWorkOS()` factory with compile-time type safety for
public vs confidential clients
- **Files:** `src/workos.ts`
- **Benefit:** TypeScript will error at compile time if you try to use
methods unavailable to public clients
- **Example:**
  ```typescript
  import { createWorkOS } from '@workos-inc/node';

  // Public client - only PKCE methods available
  const publicClient = createWorkOS({ clientId: 'client_123' });
publicClient.userManagement.getAuthorizationUrlWithPKCE({ ... }); // ✅
Works
  publicClient.userManagement.listUsers(); // ❌ TypeScript error

  // Confidential client - full access
const serverClient = createWorkOS({ apiKey: 'sk_...', clientId:
'client_123' });
  serverClient.userManagement.listUsers(); // ✅ Works
  ```

**20. Universal Runtime Support** (NON-BREAKING)
- **Improved:** Better support for Deno, Bun, and Cloudflare Workers
- **Added:** Conditional exports in package.json for runtime-specific
entry points
- **Files:** `package.json` (exports), `src/index.worker.ts`
- **Example:**
  ```typescript
  // Cloudflare Workers
  import { WorkOS } from '@workos-inc/node/worker';

  // Deno
  import { WorkOS } from 'npm:@workos-inc/node';

  // Bun (same as Node.js)
  import { WorkOS } from '@workos-inc/node';
  ```

**21. Environment Variable Helper** (NON-BREAKING)
- **Added:** Internal `getEnv()` helper for better cross-runtime
environment variable access
- **Files:** `src/common/utils/env.ts`
- **Benefit:** Works consistently across Node.js, Deno, Cloudflare
Workers, etc.

**22. Pagination Improvements** (NON-BREAKING)
- **Changed:** `AutoPaginatable` now properly defaults
`PaginationOptions` generic parameter
- **Files:** `src/common/utils/pagination.ts`
- **Benefit:** Better TypeScript inference and type safety

**23. Runtime Analytics** (NON-BREAKING)
- **Added:** Runtime information included in User-Agent string for
better debugging
- **Files:** `src/workos.ts`
- **Impact:** Helps identify runtime-specific issues

---

## INTERNAL IMPROVEMENTS

**24. Linting Migration** (Internal)
- **Changed:** Migrated from TSLint to ESLint with flat config
- **Added:** `eslint.config.mjs`
- **Removed:** `tslint.json`
- **Impact:** Better code quality checks, modern linting setup

**25. Runtime Testing** (Internal)
- **Added:** New GitHub Actions workflow for testing across multiple
runtimes
- **Added:** Ecosystem check script (`scripts/ecosystem-check.ts`)
- **Files:** `.github/workflows/runtime-tests.yml`
- **Benefit:** Ensures SDK works correctly in all supported runtimes

**26. Dependency Updates** (Internal)
- **Updated:** All dependencies to latest compatible versions
- **Updated:** Development tooling (Jest 30, TypeScript 5.9, etc.)
- **Removed:** External `leb` and `qs` packages - replaced with internal
vanilla implementations
- **Files:** `package.json`, `package-lock.json`

**27. Test Infrastructure** (Internal)
- **Updated:** Jest configuration migrated to CommonJS
- **Added:** Jest ESM transform
- **Files:** `jest.config.cjs`, `jest-transform-esm.cjs`
- **Updated:** Worker test environment with latest Miniflare

**28. Dynamic jose Import** (Internal)
- **Added:** Dynamic import wrapper for `jose` to support Node.js
20.15-20.18 compatibility
- **Files:** `src/common/utils/jose.ts`
- **Benefit:** Wider Node.js version compatibility

**29. Runtime-Agnostic UUIDs** (Internal)
- **Changed:** Now uses `globalThis.crypto.randomUUID` instead of
Node-specific crypto
- **Files:** Various
- **Benefit:** Better cross-runtime compatibility

---

## REMOVED (Previously Announced)

**30. `/client` Entry Point Removed** (BREAKING)
- **Removed:** The `@workos-inc/node/client` entry point
- **Migration:** Use the main SDK without an API key instead:
  ```typescript
  // Old approach (v8 beta)
  import { userManagement } from '@workos-inc/node/client';
  const url = userManagement.getAuthorizationUrl({ ... });

  // New approach (v8 final)
  import { WorkOS } from '@workos-inc/node';
  const workos = new WorkOS({ clientId: 'client_...' });
  const url = workos.userManagement.getAuthorizationUrl({ ... });
  ```

---

## Files Changed Summary

- **Major additions**: PKCE support, createWorkOS factory,
runtime-specific exports, environment helper
- **Major deletions**: Internal HTTP/crypto providers, deprecated
methods, legacy event types, `/client` entry point
- **Configuration**: New build system (tsdown), new linting (ESLint),
updated Jest

---

## Migration Guide

See [`docs/V8_MIGRATION_GUIDE.md`](./docs/V8_MIGRATION_GUIDE.md) for
detailed migration instructions.

---

## Testing

- All existing tests updated and passing
- Runtime compatibility tests added
- Worker environment tests updated
- Ecosystem check script validates multi-runtime support

---------

Co-authored-by: Kendall Strautman Swarthout <36613477+kendallstrautman@users.noreply.github.com>
Co-authored-by: Matt Dzwonczyk <9063128+mattgd@users.noreply.github.com>
Co-authored-by: William <william@workos.com>
Co-authored-by: Julius Marminge <jmarminge@gmail.com>
N
Nick Nisi committed
6d370ba0044f986f55725ff7bd61ace8fcf92665
Parent: 3bfab22
Committed by GitHub <noreply@github.com> on 1/12/2026, 4:47:20 PM