@workos-inc/node 7.34.0 → 7.35.1

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.
@@ -1,5 +1,6 @@
1
1
  import { CryptoProvider } from '../common/crypto/crypto-provider';
2
- import { AuthenticationActionResponseData, ResponsePayload, UserRegistrationActionResponseData } from './interfaces/response-payload';
2
+ import { ActionContext } from './interfaces/action.interface';
3
+ import { AuthenticationActionResponseData, ResponsePayload, UserRegistrationActionResponseData } from './interfaces/response-payload.interface';
3
4
  export declare class Actions {
4
5
  private signatureProvider;
5
6
  constructor(cryptoProvider: CryptoProvider);
@@ -16,4 +17,10 @@ export declare class Actions {
16
17
  payload: ResponsePayload;
17
18
  signature: string;
18
19
  }>;
20
+ constructAction({ payload, sigHeader, secret, tolerance, }: {
21
+ payload: unknown;
22
+ sigHeader: string;
23
+ secret: string;
24
+ tolerance?: number;
25
+ }): Promise<ActionContext>;
19
26
  }
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.Actions = void 0;
13
13
  const crypto_1 = require("../common/crypto");
14
14
  const unreachable_1 = require("../common/utils/unreachable");
15
+ const action_serializer_1 = require("./serializers/action.serializer");
15
16
  class Actions {
16
17
  constructor(cryptoProvider) {
17
18
  this.signatureProvider = new crypto_1.SignatureProvider(cryptoProvider);
@@ -49,5 +50,12 @@ class Actions {
49
50
  return response;
50
51
  });
51
52
  }
53
+ constructAction({ payload, sigHeader, secret, tolerance = 300, }) {
54
+ return __awaiter(this, void 0, void 0, function* () {
55
+ const options = { payload, sigHeader, secret, tolerance };
56
+ yield this.verifyHeader(options);
57
+ return (0, action_serializer_1.deserializeAction)(payload);
58
+ });
59
+ }
52
60
  }
53
61
  exports.Actions = Actions;
@@ -14,7 +14,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  const crypto_1 = __importDefault(require("crypto"));
16
16
  const workos_1 = require("../workos");
17
- const action_context_json_1 = __importDefault(require("./fixtures/action-context.json"));
17
+ const authentication_action_context_json_1 = __importDefault(require("./fixtures/authentication-action-context.json"));
18
+ const user_registration_action_context_json_1 = __importDefault(require("./fixtures/user-registration-action-context.json"));
18
19
  const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
19
20
  const crypto_2 = require("../common/crypto");
20
21
  describe('Actions', () => {
@@ -22,6 +23,16 @@ describe('Actions', () => {
22
23
  beforeEach(() => {
23
24
  secret = 'secret';
24
25
  });
26
+ const makeSigHeader = (payload, secret) => {
27
+ const timestamp = Date.now() * 1000;
28
+ const unhashedString = `${timestamp}.${JSON.stringify(payload)}`;
29
+ const signatureHash = crypto_1.default
30
+ .createHmac('sha256', secret)
31
+ .update(unhashedString)
32
+ .digest()
33
+ .toString('hex');
34
+ return `t=${timestamp}, v1=${signatureHash}`;
35
+ };
25
36
  describe('signResponse', () => {
26
37
  describe('type: authentication', () => {
27
38
  it('returns a signed response', () => __awaiter(void 0, void 0, void 0, function* () {
@@ -56,23 +67,99 @@ describe('Actions', () => {
56
67
  });
57
68
  });
58
69
  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}`,
70
+ it('verifies the header', () => __awaiter(void 0, void 0, void 0, function* () {
71
+ yield expect(workos.actions.verifyHeader({
72
+ payload: authentication_action_context_json_1.default,
73
+ sigHeader: makeSigHeader(authentication_action_context_json_1.default, secret),
73
74
  secret,
75
+ })).resolves.not.toThrow();
76
+ }));
77
+ it('throws when the header is invalid', () => __awaiter(void 0, void 0, void 0, function* () {
78
+ yield expect(workos.actions.verifyHeader({
79
+ payload: authentication_action_context_json_1.default,
80
+ sigHeader: 't=123, v1=123',
81
+ secret,
82
+ })).rejects.toThrow();
83
+ }));
84
+ });
85
+ describe('constructAction', () => {
86
+ it('returns an authentication action', () => __awaiter(void 0, void 0, void 0, function* () {
87
+ const payload = authentication_action_context_json_1.default;
88
+ const sigHeader = makeSigHeader(payload, secret);
89
+ const action = yield workos.actions.constructAction({
90
+ payload,
91
+ sigHeader,
92
+ secret,
93
+ });
94
+ expect(action).toEqual({
95
+ id: '01JATCMZJY26PQ59XT9BNT0FNN',
96
+ user: {
97
+ object: 'user',
98
+ id: '01JATCHZVEC5EPANDPEZVM68Y9',
99
+ email: 'jane@foocorp.com',
100
+ firstName: 'Jane',
101
+ lastName: 'Doe',
102
+ emailVerified: true,
103
+ profilePictureUrl: 'https://example.com/jane.jpg',
104
+ createdAt: '2024-10-22T17:12:50.746Z',
105
+ updatedAt: '2024-10-22T17:12:50.746Z',
106
+ },
107
+ ipAddress: '50.141.123.10',
108
+ userAgent: 'Mozilla/5.0',
109
+ issuer: 'test',
110
+ object: 'authentication_action_context',
111
+ organization: {
112
+ object: 'organization',
113
+ id: '01JATCMZJY26PQ59XT9BNT0FNN',
114
+ name: 'Foo Corp',
115
+ allowProfilesOutsideOrganization: false,
116
+ domains: [],
117
+ createdAt: '2024-10-22T17:12:50.746Z',
118
+ updatedAt: '2024-10-22T17:12:50.746Z',
119
+ },
120
+ organizationMembership: {
121
+ object: 'organization_membership',
122
+ id: '01JATCNVYCHT1SZGENR4QTXKRK',
123
+ userId: '01JATCHZVEC5EPANDPEZVM68Y9',
124
+ organizationId: '01JATCMZJY26PQ59XT9BNT0FNN',
125
+ role: {
126
+ slug: 'member',
127
+ },
128
+ status: 'active',
129
+ createdAt: '2024-10-22T17:12:50.746Z',
130
+ updatedAt: '2024-10-22T17:12:50.746Z',
131
+ },
132
+ });
133
+ }));
134
+ it('returns a user registration action', () => __awaiter(void 0, void 0, void 0, function* () {
135
+ const payload = user_registration_action_context_json_1.default;
136
+ const sigHeader = makeSigHeader(payload, secret);
137
+ const action = yield workos.actions.constructAction({
138
+ payload,
139
+ sigHeader,
140
+ secret,
141
+ });
142
+ expect(action).toEqual({
143
+ id: '01JATCMZJY26PQ59XT9BNT0FNN',
144
+ object: 'user_registration_action_context',
145
+ userData: {
146
+ object: 'user_data',
147
+ email: 'jane@foocorp.com',
148
+ firstName: 'Jane',
149
+ lastName: 'Doe',
150
+ },
151
+ ipAddress: '50.141.123.10',
152
+ userAgent: 'Mozilla/5.0',
153
+ invitation: expect.objectContaining({
154
+ object: 'invitation',
155
+ id: '01JBVZWH8HJ855YZ5BWHG1WNZN',
156
+ email: 'jane@foocorp.com',
157
+ expiresAt: '2024-10-22T17:12:50.746Z',
158
+ createdAt: '2024-10-21T17:12:50.746Z',
159
+ updatedAt: '2024-10-21T17:12:50.746Z',
160
+ acceptedAt: '2024-10-22T17:13:50.746Z',
161
+ }),
74
162
  });
75
- expect(spy).toHaveBeenCalled();
76
163
  }));
77
164
  });
78
165
  });
@@ -1,4 +1,5 @@
1
1
  {
2
+ "id": "01JATCMZJY26PQ59XT9BNT0FNN",
2
3
  "user": {
3
4
  "object": "user",
4
5
  "id": "01JATCHZVEC5EPANDPEZVM68Y9",
@@ -0,0 +1,24 @@
1
+ {
2
+ "id": "01JATCMZJY26PQ59XT9BNT0FNN",
3
+ "user_data": {
4
+ "object": "user_data",
5
+ "email": "jane@foocorp.com",
6
+ "first_name": "Jane",
7
+ "last_name": "Doe"
8
+ },
9
+ "ip_address": "50.141.123.10",
10
+ "user_agent": "Mozilla/5.0",
11
+ "object": "user_registration_action_context",
12
+ "invitation": {
13
+ "object": "invitation",
14
+ "id": "01JBVZWH8HJ855YZ5BWHG1WNZN",
15
+ "email": "jane@foocorp.com",
16
+ "expires_at": "2024-10-22T17:12:50.746Z",
17
+ "created_at": "2024-10-21T17:12:50.746Z",
18
+ "updated_at": "2024-10-21T17:12:50.746Z",
19
+ "accepted_at": "2024-10-22T17:13:50.746Z",
20
+ "revoked_at": null,
21
+ "organization_id": "01JBW46BTKAA98WZN8826XQ2YP",
22
+ "inviter_user_id": "01JBVZWAEPWAE3YYKBVT0AF81F"
23
+ }
24
+ }
@@ -0,0 +1,53 @@
1
+ import { Organization, OrganizationResponse } from '../../organizations/interfaces';
2
+ import { Invitation, InvitationResponse, OrganizationMembership, OrganizationMembershipResponse, User, UserResponse } from '../../user-management/interfaces';
3
+ interface AuthenticationActionContext {
4
+ id: string;
5
+ object: 'authentication_action_context';
6
+ user: User;
7
+ organization?: Organization;
8
+ organizationMembership?: OrganizationMembership;
9
+ ipAddress?: string;
10
+ userAgent?: string;
11
+ issuer?: string;
12
+ }
13
+ export interface UserData {
14
+ object: 'user_data';
15
+ email: string;
16
+ firstName: string;
17
+ lastName: string;
18
+ }
19
+ interface UserRegistrationActionContext {
20
+ id: string;
21
+ object: 'user_registration_action_context';
22
+ userData: UserData;
23
+ invitation?: Invitation;
24
+ ipAddress?: string;
25
+ userAgent?: string;
26
+ }
27
+ export type ActionContext = AuthenticationActionContext | UserRegistrationActionContext;
28
+ interface AuthenticationActionPayload {
29
+ id: string;
30
+ object: 'authentication_action_context';
31
+ user: UserResponse;
32
+ organization?: OrganizationResponse;
33
+ organization_membership?: OrganizationMembershipResponse;
34
+ ip_address?: string;
35
+ user_agent?: string;
36
+ issuer?: string;
37
+ }
38
+ export interface UserDataPayload {
39
+ object: 'user_data';
40
+ email: string;
41
+ first_name: string;
42
+ last_name: string;
43
+ }
44
+ export interface UserRegistrationActionPayload {
45
+ id: string;
46
+ object: 'user_registration_action_context';
47
+ user_data: UserDataPayload;
48
+ invitation?: InvitationResponse;
49
+ ip_address?: string;
50
+ user_agent?: string;
51
+ }
52
+ export type ActionPayload = AuthenticationActionPayload | UserRegistrationActionPayload;
53
+ export {};
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ import { ActionContext, ActionPayload } from '../interfaces/action.interface';
2
+ export declare const deserializeAction: (actionPayload: ActionPayload) => ActionContext;
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deserializeAction = void 0;
4
+ const organization_serializer_1 = require("../../organizations/serializers/organization.serializer");
5
+ const serializers_1 = require("../../user-management/serializers");
6
+ const organization_membership_serializer_1 = require("../../user-management/serializers/organization-membership.serializer");
7
+ const deserializeUserData = (userData) => {
8
+ return {
9
+ object: userData.object,
10
+ email: userData.email,
11
+ firstName: userData.first_name,
12
+ lastName: userData.last_name,
13
+ };
14
+ };
15
+ const deserializeAction = (actionPayload) => {
16
+ switch (actionPayload.object) {
17
+ case 'user_registration_action_context':
18
+ return {
19
+ id: actionPayload.id,
20
+ object: actionPayload.object,
21
+ userData: deserializeUserData(actionPayload.user_data),
22
+ invitation: actionPayload.invitation
23
+ ? (0, serializers_1.deserializeInvitation)(actionPayload.invitation)
24
+ : undefined,
25
+ ipAddress: actionPayload.ip_address,
26
+ userAgent: actionPayload.user_agent,
27
+ };
28
+ case 'authentication_action_context':
29
+ return {
30
+ id: actionPayload.id,
31
+ object: actionPayload.object,
32
+ user: (0, serializers_1.deserializeUser)(actionPayload.user),
33
+ organization: actionPayload.organization
34
+ ? (0, organization_serializer_1.deserializeOrganization)(actionPayload.organization)
35
+ : undefined,
36
+ organizationMembership: actionPayload.organization_membership
37
+ ? (0, organization_membership_serializer_1.deserializeOrganizationMembership)(actionPayload.organization_membership)
38
+ : undefined,
39
+ ipAddress: actionPayload.ip_address,
40
+ userAgent: actionPayload.user_agent,
41
+ issuer: actionPayload.issuer,
42
+ };
43
+ }
44
+ };
45
+ exports.deserializeAction = deserializeAction;
@@ -19,7 +19,10 @@ class EdgeIronSessionProvider extends iron_session_provider_1.IronSessionProvide
19
19
  /** @override */
20
20
  sealData(data, options) {
21
21
  return __awaiter(this, void 0, void 0, function* () {
22
- return (0, edge_1.sealData)(data, options);
22
+ // The iron-session default ttl is 14 days, which can be problematic if the WorkOS session is configured to be > 14 days.
23
+ // In that case the session expires and can't be refreshed, so we set the ttl to 0 to set it to the max possible value.
24
+ const sealOptions = Object.assign(Object.assign({}, options), { ttl: 0 });
25
+ return (0, edge_1.sealData)(data, sealOptions);
23
26
  });
24
27
  }
25
28
  /** @override */
@@ -19,7 +19,10 @@ class WebIronSessionProvider extends iron_session_provider_1.IronSessionProvider
19
19
  /** @override */
20
20
  sealData(data, options) {
21
21
  return __awaiter(this, void 0, void 0, function* () {
22
- return (0, iron_session_1.sealData)(data, options);
22
+ // The iron-session default ttl is 14 days, which can be problematic if the WorkOS session is configured to be > 14 days.
23
+ // In that case the session expires and can't be refreshed, so we set the ttl to 0 to set it to the max possible value.
24
+ const sealOptions = Object.assign(Object.assign({}, options), { ttl: 0 });
25
+ return (0, iron_session_1.sealData)(data, sealOptions);
23
26
  });
24
27
  }
25
28
  /** @override */
@@ -8,6 +8,7 @@ export interface Invitation {
8
8
  expiresAt: string;
9
9
  organizationId: string | null;
10
10
  inviterUserId: string | null;
11
+ acceptedUserId: string | null;
11
12
  token: string;
12
13
  acceptInvitationUrl: string;
13
14
  createdAt: string;
@@ -23,6 +24,7 @@ export interface InvitationEvent {
23
24
  expiresAt: string;
24
25
  organizationId: string | null;
25
26
  inviterUserId: string | null;
27
+ acceptedUserId: string | null;
26
28
  createdAt: string;
27
29
  updatedAt: string;
28
30
  }
@@ -36,6 +38,7 @@ export interface InvitationResponse {
36
38
  expires_at: string;
37
39
  organization_id: string | null;
38
40
  inviter_user_id: string | null;
41
+ accepted_user_id: string | null;
39
42
  token: string;
40
43
  accept_invitation_url: string;
41
44
  created_at: string;
@@ -51,6 +54,7 @@ export interface InvitationEventResponse {
51
54
  expires_at: string;
52
55
  organization_id: string | null;
53
56
  inviter_user_id: string | null;
57
+ accepted_user_id: string | null;
54
58
  created_at: string;
55
59
  updated_at: string;
56
60
  }
@@ -11,6 +11,7 @@ const deserializeInvitation = (invitation) => ({
11
11
  expiresAt: invitation.expires_at,
12
12
  organizationId: invitation.organization_id,
13
13
  inviterUserId: invitation.inviter_user_id,
14
+ acceptedUserId: invitation.accepted_user_id,
14
15
  token: invitation.token,
15
16
  acceptInvitationUrl: invitation.accept_invitation_url,
16
17
  createdAt: invitation.created_at,
@@ -27,6 +28,7 @@ const deserializeInvitationEvent = (invitation) => ({
27
28
  expiresAt: invitation.expires_at,
28
29
  organizationId: invitation.organization_id,
29
30
  inviterUserId: invitation.inviter_user_id,
31
+ acceptedUserId: invitation.accepted_user_id,
30
32
  createdAt: invitation.created_at,
31
33
  updatedAt: invitation.updated_at,
32
34
  });
@@ -100,6 +100,7 @@ export declare class UserManagement {
100
100
  findInvitationByToken(invitationToken: string): Promise<Invitation>;
101
101
  listInvitations(options: ListInvitationsOptions): Promise<AutoPaginatable<Invitation>>;
102
102
  sendInvitation(payload: SendInvitationOptions): Promise<Invitation>;
103
+ acceptInvitation(invitationId: string): Promise<Invitation>;
103
104
  revokeInvitation(invitationId: string): Promise<Invitation>;
104
105
  revokeSession(payload: RevokeSessionOptions): Promise<void>;
105
106
  getAuthorizationUrl({ connectionId, codeChallenge, codeChallengeMethod, context, clientId, domainHint, loginHint, organizationId, provider, redirectUri, state, screenHint, }: AuthorizationURLOptions): string;
@@ -489,6 +489,12 @@ class UserManagement {
489
489
  return (0, invitation_serializer_1.deserializeInvitation)(data);
490
490
  });
491
491
  }
492
+ acceptInvitation(invitationId) {
493
+ return __awaiter(this, void 0, void 0, function* () {
494
+ const { data } = yield this.workos.post(`/user_management/invitations/${invitationId}/accept`, null);
495
+ return (0, invitation_serializer_1.deserializeInvitation)(data);
496
+ });
497
+ }
492
498
  revokeInvitation(invitationId) {
493
499
  return __awaiter(this, void 0, void 0, function* () {
494
500
  const { data } = yield this.workos.post(`/user_management/invitations/${invitationId}/revoke`, null);
@@ -1425,6 +1425,20 @@ describe('UserManagement', () => {
1425
1425
  });
1426
1426
  }));
1427
1427
  });
1428
+ describe('acceptInvitation', () => {
1429
+ it('sends an Accept Invitation request', () => __awaiter(void 0, void 0, void 0, function* () {
1430
+ const invitationId = 'invitation_01H5JQDV7R7ATEYZDEG0W5PRYS';
1431
+ (0, test_utils_1.fetchOnce)(Object.assign(Object.assign({}, invitation_json_1.default), { state: 'accepted', accepted_user_id: 'user_01HGK4K4PXNSG85RNNV0GXYP5W' }));
1432
+ const response = yield workos.userManagement.acceptInvitation(invitationId);
1433
+ expect((0, test_utils_1.fetchURL)()).toContain(`/user_management/invitations/${invitationId}/accept`);
1434
+ expect(response).toMatchObject({
1435
+ object: 'invitation',
1436
+ email: 'dane@workos.com',
1437
+ state: 'accepted',
1438
+ acceptedUserId: 'user_01HGK4K4PXNSG85RNNV0GXYP5W',
1439
+ });
1440
+ }));
1441
+ });
1428
1442
  describe('revokeInvitation', () => {
1429
1443
  it('send a Revoke Invitation request', () => __awaiter(void 0, void 0, void 0, function* () {
1430
1444
  const invitationId = 'invitation_01H5JQDV7R7ATEYZDEG0W5PRYS';
package/lib/workos.js CHANGED
@@ -29,7 +29,7 @@ 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
31
  const actions_1 = require("./actions/actions");
32
- const VERSION = '7.34.0';
32
+ const VERSION = '7.35.1';
33
33
  const DEFAULT_HOSTNAME = 'api.workos.com';
34
34
  const HEADER_AUTHORIZATION = 'Authorization';
35
35
  const HEADER_IDEMPOTENCY_KEY = 'Idempotency-Key';
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "7.34.0",
2
+ "version": "7.35.1",
3
3
  "name": "@workos-inc/node",
4
4
  "author": "WorkOS",
5
5
  "description": "A Node wrapper for the WorkOS API",