@workos-inc/node 7.31.0-beta.actions1 → 7.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/lib/index.d.ts +0 -3
  2. package/lib/index.js +0 -12
  3. package/lib/index.worker.d.ts +0 -3
  4. package/lib/index.worker.js +0 -6
  5. package/lib/user-management/interfaces/authentication-response.interface.d.ts +3 -0
  6. package/lib/user-management/interfaces/index.d.ts +2 -3
  7. package/lib/user-management/interfaces/index.js +2 -3
  8. package/lib/user-management/interfaces/oauth-tokens.interface.d.ts +12 -0
  9. package/lib/user-management/serializers/authentication-response.serializer.js +3 -2
  10. package/lib/user-management/serializers/oauth-tokens.serializer.d.ts +2 -0
  11. package/lib/user-management/serializers/oauth-tokens.serializer.js +12 -0
  12. package/lib/user-management/user-management.spec.js +28 -0
  13. package/lib/webhooks/webhooks.d.ts +9 -9
  14. package/lib/webhooks/webhooks.js +36 -11
  15. package/lib/webhooks/webhooks.spec.js +46 -23
  16. package/lib/workos.d.ts +0 -3
  17. package/lib/workos.js +1 -6
  18. package/lib/workos.spec.js +1 -5
  19. package/package.json +1 -1
  20. package/lib/actions/actions.d.ts +0 -19
  21. package/lib/actions/actions.js +0 -53
  22. package/lib/actions/actions.spec.d.ts +0 -1
  23. package/lib/actions/actions.spec.js +0 -78
  24. package/lib/actions/fixtures/action-context.json +0 -39
  25. package/lib/actions/interfaces/response-payload.d.ts +0 -23
  26. package/lib/common/crypto/CryptoProvider.d.ts +0 -32
  27. package/lib/common/crypto/CryptoProvider.js +0 -13
  28. package/lib/common/crypto/CryptoProvider.spec.d.ts +0 -1
  29. package/lib/common/crypto/CryptoProvider.spec.js +0 -57
  30. package/lib/common/crypto/NodeCryptoProvider.d.ts +0 -12
  31. package/lib/common/crypto/NodeCryptoProvider.js +0 -73
  32. package/lib/common/crypto/SignatureProvider.d.ts +0 -13
  33. package/lib/common/crypto/SignatureProvider.js +0 -53
  34. package/lib/common/crypto/SignatureProvider.spec.d.ts +0 -1
  35. package/lib/common/crypto/SignatureProvider.spec.js +0 -66
  36. package/lib/common/crypto/SubtleCryptoProvider.d.ts +0 -15
  37. package/lib/common/crypto/SubtleCryptoProvider.js +0 -75
  38. package/lib/common/crypto/index.d.ts +0 -4
  39. package/lib/common/crypto/index.js +0 -20
  40. package/lib/common/net/index.d.ts +0 -5
  41. package/lib/common/net/index.js +0 -31
  42. package/lib/common/utils/unreachable.d.ts +0 -10
  43. package/lib/common/utils/unreachable.js +0 -18
  44. /package/lib/{actions/interfaces/response-payload.js → user-management/interfaces/oauth-tokens.interface.js} +0 -0
package/lib/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { HttpClient } from './common/net/http-client';
2
- import { Actions } from './actions/actions';
3
2
  import { Webhooks } from './webhooks/webhooks';
4
3
  import { WorkOS } from './workos';
5
4
  import { WorkOSOptions } from './common/interfaces';
@@ -24,8 +23,6 @@ declare class WorkOSNode extends WorkOS {
24
23
  /** @override */
25
24
  createWebhookClient(): Webhooks;
26
25
  /** @override */
27
- createActionsClient(): Actions;
28
- /** @override */
29
26
  createIronSessionProvider(): IronSessionProvider;
30
27
  /** @override */
31
28
  emitWarning(warning: string): void;
package/lib/index.js CHANGED
@@ -19,7 +19,6 @@ const node_crypto_provider_1 = require("./common/crypto/node-crypto-provider");
19
19
  const subtle_crypto_provider_1 = require("./common/crypto/subtle-crypto-provider");
20
20
  const fetch_client_1 = require("./common/net/fetch-client");
21
21
  const node_client_1 = require("./common/net/node-client");
22
- const actions_1 = require("./actions/actions");
23
22
  const webhooks_1 = require("./webhooks/webhooks");
24
23
  const workos_1 = require("./workos");
25
24
  const web_iron_session_provider_1 = require("./common/iron-session/web-iron-session-provider");
@@ -62,17 +61,6 @@ class WorkOSNode extends workos_1.WorkOS {
62
61
  return new webhooks_1.Webhooks(cryptoProvider);
63
62
  }
64
63
  /** @override */
65
- createActionsClient() {
66
- let cryptoProvider;
67
- if (typeof crypto !== 'undefined' && typeof crypto.subtle !== 'undefined') {
68
- cryptoProvider = new subtle_crypto_provider_1.SubtleCryptoProvider();
69
- }
70
- else {
71
- cryptoProvider = new node_crypto_provider_1.NodeCryptoProvider();
72
- }
73
- return new actions_1.Actions(cryptoProvider);
74
- }
75
- /** @override */
76
64
  createIronSessionProvider() {
77
65
  return new web_iron_session_provider_1.WebIronSessionProvider();
78
66
  }
@@ -1,4 +1,3 @@
1
- import { Actions } from './actions/actions';
2
1
  import { IronSessionProvider } from './common/iron-session/iron-session-provider';
3
2
  import { HttpClient } from './common/net/http-client';
4
3
  import { WorkOSOptions } from './index.worker';
@@ -22,8 +21,6 @@ declare class WorkOSWorker extends WorkOS {
22
21
  /** @override */
23
22
  createWebhookClient(): Webhooks;
24
23
  /** @override */
25
- createActionsClient(): Actions;
26
- /** @override */
27
24
  createIronSessionProvider(): IronSessionProvider;
28
25
  /** @override */
29
26
  emitWarning(warning: string): void;
@@ -15,7 +15,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  exports.WorkOS = void 0;
18
- const actions_1 = require("./actions/actions");
19
18
  const subtle_crypto_provider_1 = require("./common/crypto/subtle-crypto-provider");
20
19
  const edge_iron_session_provider_1 = require("./common/iron-session/edge-iron-session-provider");
21
20
  const fetch_client_1 = require("./common/net/fetch-client");
@@ -45,11 +44,6 @@ class WorkOSWorker extends workos_1.WorkOS {
45
44
  return new webhooks_1.Webhooks(cryptoProvider);
46
45
  }
47
46
  /** @override */
48
- createActionsClient() {
49
- const cryptoProvider = new subtle_crypto_provider_1.SubtleCryptoProvider();
50
- return new actions_1.Actions(cryptoProvider);
51
- }
52
- /** @override */
53
47
  createIronSessionProvider() {
54
48
  return new edge_iron_session_provider_1.EdgeIronSessionProvider();
55
49
  }
@@ -1,4 +1,5 @@
1
1
  import { Impersonator, ImpersonatorResponse } from './impersonator.interface';
2
+ import { OauthTokens, OauthTokensResponse } from './oauth-tokens.interface';
2
3
  import { User, UserResponse } from './user.interface';
3
4
  type AuthenticationMethod = 'SSO' | 'Password' | 'AppleOAuth' | 'GitHubOAuth' | 'GoogleOAuth' | 'MicrosoftOAuth' | 'MagicAuth' | 'Impersonation';
4
5
  export interface AuthenticationResponse {
@@ -9,6 +10,7 @@ export interface AuthenticationResponse {
9
10
  impersonator?: Impersonator;
10
11
  authenticationMethod?: AuthenticationMethod;
11
12
  sealedSession?: string;
13
+ oauthTokens?: OauthTokens;
12
14
  }
13
15
  export interface AuthenticationResponseResponse {
14
16
  user: UserResponse;
@@ -17,5 +19,6 @@ export interface AuthenticationResponseResponse {
17
19
  refresh_token: string;
18
20
  impersonator?: ImpersonatorResponse;
19
21
  authentication_method?: AuthenticationMethod;
22
+ oauth_tokens?: OauthTokensResponse;
20
23
  }
21
24
  export {};
@@ -1,6 +1,3 @@
1
- export * from './authentication-event.interface';
2
- export * from './authenticate-with-magic-auth-options.interface';
3
- export * from './authenticate-with-password-options.interface';
4
1
  export * from './authenticate-with-code-options.interface';
5
2
  export * from './authenticate-with-email-verification-options.interface';
6
3
  export * from './authenticate-with-magic-auth-options.interface';
@@ -10,6 +7,7 @@ export * from './authenticate-with-password-options.interface';
10
7
  export * from './authenticate-with-refresh-token-options.interface';
11
8
  export * from './authenticate-with-session-cookie.interface';
12
9
  export * from './authenticate-with-totp-options.interface';
10
+ export * from './authentication-event.interface';
13
11
  export * from './authentication-response.interface';
14
12
  export * from './create-magic-auth-options.interface';
15
13
  export * from './create-organization-membership-options.interface';
@@ -25,6 +23,7 @@ export * from './list-invitations-options.interface';
25
23
  export * from './list-organization-memberships-options.interface';
26
24
  export * from './list-users-options.interface';
27
25
  export * from './magic-auth.interface';
26
+ export * from './oauth-tokens.interface';
28
27
  export * from './organization-membership.interface';
29
28
  export * from './password-reset.interface';
30
29
  export * from './refresh-and-seal-session-data.interface';
@@ -14,9 +14,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./authentication-event.interface"), exports);
18
- __exportStar(require("./authenticate-with-magic-auth-options.interface"), exports);
19
- __exportStar(require("./authenticate-with-password-options.interface"), exports);
20
17
  __exportStar(require("./authenticate-with-code-options.interface"), exports);
21
18
  __exportStar(require("./authenticate-with-email-verification-options.interface"), exports);
22
19
  __exportStar(require("./authenticate-with-magic-auth-options.interface"), exports);
@@ -26,6 +23,7 @@ __exportStar(require("./authenticate-with-password-options.interface"), exports)
26
23
  __exportStar(require("./authenticate-with-refresh-token-options.interface"), exports);
27
24
  __exportStar(require("./authenticate-with-session-cookie.interface"), exports);
28
25
  __exportStar(require("./authenticate-with-totp-options.interface"), exports);
26
+ __exportStar(require("./authentication-event.interface"), exports);
29
27
  __exportStar(require("./authentication-response.interface"), exports);
30
28
  __exportStar(require("./create-magic-auth-options.interface"), exports);
31
29
  __exportStar(require("./create-organization-membership-options.interface"), exports);
@@ -41,6 +39,7 @@ __exportStar(require("./list-invitations-options.interface"), exports);
41
39
  __exportStar(require("./list-organization-memberships-options.interface"), exports);
42
40
  __exportStar(require("./list-users-options.interface"), exports);
43
41
  __exportStar(require("./magic-auth.interface"), exports);
42
+ __exportStar(require("./oauth-tokens.interface"), exports);
44
43
  __exportStar(require("./organization-membership.interface"), exports);
45
44
  __exportStar(require("./password-reset.interface"), exports);
46
45
  __exportStar(require("./refresh-and-seal-session-data.interface"), exports);
@@ -0,0 +1,12 @@
1
+ export interface OauthTokens {
2
+ accessToken: string;
3
+ refreshToken: string;
4
+ expiresAt: number;
5
+ scopes: string[];
6
+ }
7
+ export interface OauthTokensResponse {
8
+ access_token: string;
9
+ refresh_token: string;
10
+ expires_at: number;
11
+ scopes: string[];
12
+ }
@@ -12,9 +12,10 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  };
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
14
  exports.deserializeAuthenticationResponse = void 0;
15
+ const oauth_tokens_serializer_1 = require("./oauth-tokens.serializer");
15
16
  const user_serializer_1 = require("./user.serializer");
16
17
  const deserializeAuthenticationResponse = (authenticationResponse) => {
17
- const { user, organization_id, access_token, refresh_token, authentication_method, impersonator } = authenticationResponse, rest = __rest(authenticationResponse, ["user", "organization_id", "access_token", "refresh_token", "authentication_method", "impersonator"]);
18
- return Object.assign({ user: (0, user_serializer_1.deserializeUser)(user), organizationId: organization_id, accessToken: access_token, refreshToken: refresh_token, impersonator, authenticationMethod: authentication_method }, rest);
18
+ const { user, organization_id, access_token, refresh_token, authentication_method, impersonator, oauth_tokens } = authenticationResponse, rest = __rest(authenticationResponse, ["user", "organization_id", "access_token", "refresh_token", "authentication_method", "impersonator", "oauth_tokens"]);
19
+ return Object.assign({ user: (0, user_serializer_1.deserializeUser)(user), organizationId: organization_id, accessToken: access_token, refreshToken: refresh_token, impersonator, authenticationMethod: authentication_method, oauthTokens: (0, oauth_tokens_serializer_1.deserializeOauthTokens)(oauth_tokens) }, rest);
19
20
  };
20
21
  exports.deserializeAuthenticationResponse = deserializeAuthenticationResponse;
@@ -0,0 +1,2 @@
1
+ import { OauthTokensResponse, OauthTokens } from '../interfaces';
2
+ export declare const deserializeOauthTokens: (oauthTokens?: OauthTokensResponse) => OauthTokens | undefined;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deserializeOauthTokens = void 0;
4
+ const deserializeOauthTokens = (oauthTokens) => oauthTokens
5
+ ? {
6
+ accessToken: oauthTokens.access_token,
7
+ refreshToken: oauthTokens.refresh_token,
8
+ expiresAt: oauthTokens.expires_at,
9
+ scopes: oauthTokens.scopes,
10
+ }
11
+ : undefined;
12
+ exports.deserializeOauthTokens = deserializeOauthTokens;
@@ -374,6 +374,34 @@ describe('UserManagement', () => {
374
374
  }));
375
375
  });
376
376
  });
377
+ describe('when oauth_tokens is present', () => {
378
+ it('deserializes oauth_tokens', () => __awaiter(void 0, void 0, void 0, function* () {
379
+ (0, test_utils_1.fetchOnce)({
380
+ user: user_json_1.default,
381
+ oauth_tokens: {
382
+ access_token: 'access_token',
383
+ refresh_token: 'refresh',
384
+ expires_at: 123,
385
+ scopes: ['read:users'],
386
+ },
387
+ });
388
+ const resp = yield workos.userManagement.authenticateWithCode({
389
+ clientId: 'proj_whatever',
390
+ code: 'or this',
391
+ });
392
+ expect(resp).toMatchObject({
393
+ user: {
394
+ email: 'test01@example.com',
395
+ },
396
+ oauthTokens: {
397
+ accessToken: 'access_token',
398
+ refreshToken: 'refresh',
399
+ expiresAt: 123,
400
+ scopes: ['read:users'],
401
+ },
402
+ });
403
+ }));
404
+ });
377
405
  });
378
406
  describe('authenticateWithRefreshToken', () => {
379
407
  it('sends a refresh_token authentication request', () => __awaiter(void 0, void 0, void 0, function* () {
@@ -1,20 +1,20 @@
1
1
  import { Event } from '../common/interfaces';
2
2
  import { CryptoProvider } from '../common/crypto/crypto-provider';
3
3
  export declare class Webhooks {
4
- private signatureProvider;
4
+ private cryptoProvider;
5
5
  constructor(cryptoProvider: CryptoProvider);
6
- get verifyHeader(): ({ payload, sigHeader, secret, tolerance, }: {
7
- payload: any;
8
- sigHeader: string;
9
- secret: string;
10
- tolerance?: number | undefined;
11
- }) => Promise<boolean>;
12
- get computeSignature(): (timestamp: any, payload: any, secret: string) => Promise<string>;
13
- get getTimestampAndSignatureHash(): (sigHeader: string) => [string, string];
14
6
  constructEvent({ payload, sigHeader, secret, tolerance, }: {
15
7
  payload: unknown;
16
8
  sigHeader: string;
17
9
  secret: string;
18
10
  tolerance?: number;
19
11
  }): Promise<Event>;
12
+ verifyHeader({ payload, sigHeader, secret, tolerance, }: {
13
+ payload: any;
14
+ sigHeader: string;
15
+ secret: string;
16
+ tolerance?: number;
17
+ }): Promise<boolean>;
18
+ getTimestampAndSignatureHash(sigHeader: string): [string, string];
19
+ computeSignature(timestamp: any, payload: any, secret: string): Promise<string>;
20
20
  }
@@ -10,20 +10,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.Webhooks = void 0;
13
+ const exceptions_1 = require("../common/exceptions");
13
14
  const serializers_1 = require("../common/serializers");
14
- const SignatureProvider_1 = require("../common/crypto/SignatureProvider");
15
15
  class Webhooks {
16
16
  constructor(cryptoProvider) {
17
- this.signatureProvider = new SignatureProvider_1.SignatureProvider(cryptoProvider);
18
- }
19
- get verifyHeader() {
20
- return this.signatureProvider.verifyHeader.bind(this.signatureProvider);
21
- }
22
- get computeSignature() {
23
- return this.signatureProvider.computeSignature.bind(this.signatureProvider);
24
- }
25
- get getTimestampAndSignatureHash() {
26
- return this.signatureProvider.getTimestampAndSignatureHash.bind(this.signatureProvider);
17
+ this.cryptoProvider = cryptoProvider;
27
18
  }
28
19
  constructEvent({ payload, sigHeader, secret, tolerance = 180000, }) {
29
20
  return __awaiter(this, void 0, void 0, function* () {
@@ -33,5 +24,39 @@ class Webhooks {
33
24
  return (0, serializers_1.deserializeEvent)(webhookPayload);
34
25
  });
35
26
  }
27
+ verifyHeader({ payload, sigHeader, secret, tolerance = 180000, }) {
28
+ return __awaiter(this, void 0, void 0, function* () {
29
+ const [timestamp, signatureHash] = this.getTimestampAndSignatureHash(sigHeader);
30
+ if (!signatureHash || Object.keys(signatureHash).length === 0) {
31
+ throw new exceptions_1.SignatureVerificationException('No signature hash found with expected scheme v1');
32
+ }
33
+ if (parseInt(timestamp, 10) < Date.now() - tolerance) {
34
+ throw new exceptions_1.SignatureVerificationException('Timestamp outside the tolerance zone');
35
+ }
36
+ const expectedSig = yield this.computeSignature(timestamp, payload, secret);
37
+ if ((yield this.cryptoProvider.secureCompare(expectedSig, signatureHash)) ===
38
+ false) {
39
+ throw new exceptions_1.SignatureVerificationException('Signature hash does not match the expected signature hash for payload');
40
+ }
41
+ return true;
42
+ });
43
+ }
44
+ getTimestampAndSignatureHash(sigHeader) {
45
+ const signature = sigHeader;
46
+ const [t, v1] = signature.split(',');
47
+ if (typeof t === 'undefined' || typeof v1 === 'undefined') {
48
+ throw new exceptions_1.SignatureVerificationException('Signature or timestamp missing');
49
+ }
50
+ const { 1: timestamp } = t.split('=');
51
+ const { 1: signatureHash } = v1.split('=');
52
+ return [timestamp, signatureHash];
53
+ }
54
+ computeSignature(timestamp, payload, secret) {
55
+ return __awaiter(this, void 0, void 0, function* () {
56
+ payload = JSON.stringify(payload);
57
+ const signedPayload = `${timestamp}.${payload}`;
58
+ return yield this.cryptoProvider.computeHMACSignatureAsync(signedPayload, secret);
59
+ });
60
+ }
36
61
  }
37
62
  exports.Webhooks = Webhooks;
@@ -17,6 +17,8 @@ const workos_1 = require("../workos");
17
17
  const webhook_json_1 = __importDefault(require("./fixtures/webhook.json"));
18
18
  const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
19
19
  const exceptions_1 = require("../common/exceptions");
20
+ const node_crypto_provider_1 = require("../common/crypto/node-crypto-provider");
21
+ const subtle_crypto_provider_1 = require("../common/crypto/subtle-crypto-provider");
20
22
  describe('Webhooks', () => {
21
23
  let payload;
22
24
  let secret;
@@ -164,34 +166,55 @@ describe('Webhooks', () => {
164
166
  });
165
167
  });
166
168
  describe('verifyHeader', () => {
167
- it('aliases to the signature provider', () => __awaiter(void 0, void 0, void 0, function* () {
168
- const spy = jest.spyOn(
169
- // tslint:disable-next-line
170
- workos.webhooks['signatureProvider'], 'verifyHeader');
171
- yield workos.webhooks.verifyHeader({
172
- payload,
173
- sigHeader: `t=${timestamp}, v1=${signatureHash}`,
174
- secret,
175
- });
176
- expect(spy).toHaveBeenCalled();
169
+ it('returns true when the signature is valid', () => __awaiter(void 0, void 0, void 0, function* () {
170
+ const sigHeader = `t=${timestamp}, v1=${signatureHash}`;
171
+ const options = { payload, sigHeader, secret };
172
+ const result = yield workos.webhooks.verifyHeader(options);
173
+ expect(result).toBeTruthy();
177
174
  }));
178
175
  });
176
+ describe('getTimestampAndSignatureHash', () => {
177
+ it('returns the timestamp and signature when the signature is valid', () => {
178
+ const sigHeader = `t=${timestamp}, v1=${signatureHash}`;
179
+ const timestampAndSignature = workos.webhooks.getTimestampAndSignatureHash(sigHeader);
180
+ expect(timestampAndSignature).toEqual([
181
+ timestamp.toString(),
182
+ signatureHash,
183
+ ]);
184
+ });
185
+ });
179
186
  describe('computeSignature', () => {
180
- it('aliases to the signature provider', () => __awaiter(void 0, void 0, void 0, function* () {
181
- const spy = jest.spyOn(
182
- // tslint:disable-next-line
183
- workos.webhooks['signatureProvider'], 'computeSignature');
184
- yield workos.webhooks.computeSignature(timestamp, payload, secret);
185
- expect(spy).toHaveBeenCalled();
187
+ it('returns the computed signature', () => __awaiter(void 0, void 0, void 0, function* () {
188
+ const signature = yield workos.webhooks.computeSignature(timestamp, payload, secret);
189
+ expect(signature).toEqual(signatureHash);
186
190
  }));
187
191
  });
188
- describe('getTimestampAndSignatureHash', () => {
189
- it('aliases to the signature provider', () => __awaiter(void 0, void 0, void 0, function* () {
190
- const spy = jest.spyOn(
192
+ describe('when in an environment that supports SubtleCrypto', () => {
193
+ it('automatically uses the subtle crypto library', () => {
191
194
  // tslint:disable-next-line
192
- workos.webhooks['signatureProvider'], 'getTimestampAndSignatureHash');
193
- workos.webhooks.getTimestampAndSignatureHash(`t=${timestamp}, v1=${signatureHash}`);
194
- expect(spy).toHaveBeenCalled();
195
- }));
195
+ expect(workos.webhooks['cryptoProvider']).toBeInstanceOf(subtle_crypto_provider_1.SubtleCryptoProvider);
196
+ });
197
+ });
198
+ describe('CryptoProvider', () => {
199
+ describe('when computing HMAC signature', () => {
200
+ it('returns the same for the Node crypto and Web Crypto versions', () => __awaiter(void 0, void 0, void 0, function* () {
201
+ const nodeCryptoProvider = new node_crypto_provider_1.NodeCryptoProvider();
202
+ const subtleCryptoProvider = new subtle_crypto_provider_1.SubtleCryptoProvider();
203
+ const stringifiedPayload = JSON.stringify(payload);
204
+ const payloadHMAC = `${timestamp}.${stringifiedPayload}`;
205
+ const nodeCompare = yield nodeCryptoProvider.computeHMACSignatureAsync(payloadHMAC, secret);
206
+ const subtleCompare = yield subtleCryptoProvider.computeHMACSignatureAsync(payloadHMAC, secret);
207
+ expect(nodeCompare).toEqual(subtleCompare);
208
+ }));
209
+ });
210
+ describe('when securely comparing', () => {
211
+ it('returns the same for the Node crypto and Web Crypto versions', () => __awaiter(void 0, void 0, void 0, function* () {
212
+ const nodeCryptoProvider = new node_crypto_provider_1.NodeCryptoProvider();
213
+ const subtleCryptoProvider = new subtle_crypto_provider_1.SubtleCryptoProvider();
214
+ const signature = yield workos.webhooks.computeSignature(timestamp, payload, secret);
215
+ expect(nodeCryptoProvider.secureCompare(signature, signatureHash)).toEqual(subtleCryptoProvider.secureCompare(signature, signatureHash));
216
+ expect(nodeCryptoProvider.secureCompare(signature, 'foo')).toEqual(subtleCryptoProvider.secureCompare(signature, 'foo'));
217
+ }));
218
+ });
196
219
  });
197
220
  });
package/lib/workos.d.ts CHANGED
@@ -14,14 +14,12 @@ import { FGA } from './fga/fga';
14
14
  import { HttpClient } from './common/net/http-client';
15
15
  import { IronSessionProvider } from './common/iron-session/iron-session-provider';
16
16
  import { Widgets } from './widgets/widgets';
17
- import { Actions } from './actions/actions';
18
17
  export declare class WorkOS {
19
18
  readonly key?: string | undefined;
20
19
  readonly options: WorkOSOptions;
21
20
  readonly baseURL: string;
22
21
  readonly client: HttpClient;
23
22
  readonly clientId?: string;
24
- readonly actions: Actions;
25
23
  readonly auditLogs: AuditLogs;
26
24
  readonly directorySync: DirectorySync;
27
25
  readonly organizations: Organizations;
@@ -37,7 +35,6 @@ export declare class WorkOS {
37
35
  readonly widgets: Widgets;
38
36
  constructor(key?: string | undefined, options?: WorkOSOptions);
39
37
  createWebhookClient(): Webhooks;
40
- createActionsClient(): Actions;
41
38
  createHttpClient(options: WorkOSOptions, userAgent: string): HttpClient;
42
39
  createIronSessionProvider(): IronSessionProvider;
43
40
  get version(): string;
package/lib/workos.js CHANGED
@@ -28,8 +28,7 @@ const http_client_1 = require("./common/net/http-client");
28
28
  const subtle_crypto_provider_1 = require("./common/crypto/subtle-crypto-provider");
29
29
  const fetch_client_1 = require("./common/net/fetch-client");
30
30
  const widgets_1 = require("./widgets/widgets");
31
- const actions_1 = require("./actions/actions");
32
- const VERSION = '7.30.1';
31
+ const VERSION = '7.31.0';
33
32
  const DEFAULT_HOSTNAME = 'api.workos.com';
34
33
  const HEADER_AUTHORIZATION = 'Authorization';
35
34
  const HEADER_IDEMPOTENCY_KEY = 'Idempotency-Key';
@@ -79,7 +78,6 @@ class WorkOS {
79
78
  userAgent += ` ${name}: ${version}`;
80
79
  }
81
80
  this.webhooks = this.createWebhookClient();
82
- this.actions = this.createActionsClient();
83
81
  // Must initialize UserManagement after baseURL is configured
84
82
  this.userManagement = new user_management_1.UserManagement(this, this.createIronSessionProvider());
85
83
  this.client = this.createHttpClient(options, userAgent);
@@ -87,9 +85,6 @@ class WorkOS {
87
85
  createWebhookClient() {
88
86
  return new webhooks_1.Webhooks(new subtle_crypto_provider_1.SubtleCryptoProvider());
89
87
  }
90
- createActionsClient() {
91
- return new actions_1.Actions(new subtle_crypto_provider_1.SubtleCryptoProvider());
92
- }
93
88
  createHttpClient(options, userAgent) {
94
89
  var _a;
95
90
  return new fetch_client_1.FetchHttpClient(this.baseURL, Object.assign(Object.assign({}, options.config), { headers: Object.assign(Object.assign({}, (_a = options.config) === null || _a === void 0 ? void 0 : _a.headers), { Authorization: `Bearer ${this.key}`, 'User-Agent': userAgent }) }));
@@ -246,12 +246,8 @@ describe('WorkOS', () => {
246
246
  const workos = new index_worker_1.WorkOS('sk_test_key');
247
247
  // tslint:disable-next-line
248
248
  expect(workos['client']).toBeInstanceOf(fetch_client_1.FetchHttpClient);
249
- expect(
250
249
  // tslint:disable-next-line
251
- workos.webhooks['signatureProvider']['cryptoProvider']).toBeInstanceOf(subtle_crypto_provider_1.SubtleCryptoProvider);
252
- expect(
253
- // tslint:disable-next-line
254
- workos.actions['signatureProvider']['cryptoProvider']).toBeInstanceOf(subtle_crypto_provider_1.SubtleCryptoProvider);
250
+ expect(workos.webhooks['cryptoProvider']).toBeInstanceOf(subtle_crypto_provider_1.SubtleCryptoProvider);
255
251
  });
256
252
  it('uses console.warn to emit warnings', () => {
257
253
  const workos = new index_worker_1.WorkOS('sk_test_key');
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "7.31.0-beta.actions1",
2
+ "version": "7.31.0",
3
3
  "name": "@workos-inc/node",
4
4
  "author": "WorkOS",
5
5
  "description": "A Node wrapper for the WorkOS API",
@@ -1,19 +0,0 @@
1
- import { CryptoProvider } from '../common/crypto/crypto-provider';
2
- import { AuthenticationActionResponseData, ResponsePayload, UserRegistrationActionResponseData } from './interfaces/response-payload';
3
- export declare class Actions {
4
- private signatureProvider;
5
- constructor(cryptoProvider: CryptoProvider);
6
- private get computeSignature();
7
- get verifyHeader(): ({ payload, sigHeader, secret, tolerance, }: {
8
- payload: any;
9
- sigHeader: string;
10
- secret: string;
11
- tolerance?: number | undefined;
12
- }) => Promise<boolean>;
13
- serializeType(type: AuthenticationActionResponseData['type'] | UserRegistrationActionResponseData['type']): "authentication_action_response" | "user_registration_action_response";
14
- signResponse(data: AuthenticationActionResponseData | UserRegistrationActionResponseData, secret: string): Promise<{
15
- object: string;
16
- payload: ResponsePayload;
17
- signature: string;
18
- }>;
19
- }
@@ -1,53 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.Actions = void 0;
13
- const crypto_1 = require("../common/crypto");
14
- const unreachable_1 = require("../common/utils/unreachable");
15
- class Actions {
16
- constructor(cryptoProvider) {
17
- this.signatureProvider = new crypto_1.SignatureProvider(cryptoProvider);
18
- }
19
- get computeSignature() {
20
- return this.signatureProvider.computeSignature.bind(this.signatureProvider);
21
- }
22
- get verifyHeader() {
23
- return this.signatureProvider.verifyHeader.bind(this.signatureProvider);
24
- }
25
- serializeType(type) {
26
- switch (type) {
27
- case 'authentication':
28
- return 'authentication_action_response';
29
- case 'user_registration':
30
- return 'user_registration_action_response';
31
- default:
32
- return (0, unreachable_1.unreachable)(type);
33
- }
34
- }
35
- signResponse(data, secret) {
36
- return __awaiter(this, void 0, void 0, function* () {
37
- let errorMessage;
38
- const { verdict, type } = data;
39
- if (verdict === 'Deny' && data.errorMessage) {
40
- errorMessage = data.errorMessage;
41
- }
42
- const responsePayload = Object.assign({ timestamp: Date.now(), verdict }, (verdict === 'Deny' &&
43
- data.errorMessage && { error_message: errorMessage }));
44
- const response = {
45
- object: this.serializeType(type),
46
- payload: responsePayload,
47
- signature: yield this.computeSignature(responsePayload.timestamp, responsePayload, secret),
48
- };
49
- return response;
50
- });
51
- }
52
- }
53
- exports.Actions = Actions;
@@ -1 +0,0 @@
1
- export {};
@@ -1,78 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- const crypto_1 = __importDefault(require("crypto"));
16
- const workos_1 = require("../workos");
17
- const action_context_json_1 = __importDefault(require("./fixtures/action-context.json"));
18
- const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
19
- const crypto_2 = require("../common/crypto");
20
- describe('Actions', () => {
21
- let secret;
22
- beforeEach(() => {
23
- secret = 'secret';
24
- });
25
- describe('signResponse', () => {
26
- describe('type: authentication', () => {
27
- it('returns a signed response', () => __awaiter(void 0, void 0, void 0, function* () {
28
- const nodeCryptoProvider = new crypto_2.NodeCryptoProvider();
29
- const response = yield workos.actions.signResponse({
30
- type: 'authentication',
31
- verdict: 'Allow',
32
- }, secret);
33
- const signedPayload = `${response.payload.timestamp}.${JSON.stringify(response.payload)}`;
34
- const expectedSig = yield nodeCryptoProvider.computeHMACSignatureAsync(signedPayload, secret);
35
- expect(response.object).toEqual('authentication_action_response');
36
- expect(response.payload.verdict).toEqual('Allow');
37
- expect(response.payload.timestamp).toBeGreaterThan(0);
38
- expect(response.signature).toEqual(expectedSig);
39
- }));
40
- });
41
- describe('type: user_registration', () => {
42
- it('returns a signed response', () => __awaiter(void 0, void 0, void 0, function* () {
43
- const nodeCryptoProvider = new crypto_2.NodeCryptoProvider();
44
- const response = yield workos.actions.signResponse({
45
- type: 'user_registration',
46
- verdict: 'Deny',
47
- errorMessage: 'User already exists',
48
- }, secret);
49
- const signedPayload = `${response.payload.timestamp}.${JSON.stringify(response.payload)}`;
50
- const expectedSig = yield nodeCryptoProvider.computeHMACSignatureAsync(signedPayload, secret);
51
- expect(response.object).toEqual('user_registration_action_response');
52
- expect(response.payload.verdict).toEqual('Deny');
53
- expect(response.payload.timestamp).toBeGreaterThan(0);
54
- expect(response.signature).toEqual(expectedSig);
55
- }));
56
- });
57
- });
58
- describe('verifyHeader', () => {
59
- it('aliases to the signature provider', () => __awaiter(void 0, void 0, void 0, function* () {
60
- const spy = jest.spyOn(
61
- // tslint:disable-next-line
62
- workos.actions['signatureProvider'], 'verifyHeader');
63
- const timestamp = Date.now() * 1000;
64
- const unhashedString = `${timestamp}.${JSON.stringify(action_context_json_1.default)}`;
65
- const signatureHash = crypto_1.default
66
- .createHmac('sha256', secret)
67
- .update(unhashedString)
68
- .digest()
69
- .toString('hex');
70
- yield workos.actions.verifyHeader({
71
- payload: action_context_json_1.default,
72
- sigHeader: `t=${timestamp}, v1=${signatureHash}`,
73
- secret,
74
- });
75
- expect(spy).toHaveBeenCalled();
76
- }));
77
- });
78
- });