@workos-inc/node 7.14.0 → 7.15.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.
@@ -6,4 +6,5 @@ export interface WorkOSOptions {
6
6
  config?: RequestInit;
7
7
  appInfo?: AppInfo;
8
8
  fetchFn?: typeof fetch;
9
+ clientId?: string;
9
10
  }
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import { HttpClient, HttpClientResponse } from './http-client';
3
2
  import { HttpClientInterface, HttpClientResponseInterface, RequestOptions } from '../interfaces/http-client.interface';
4
3
  import * as http_ from 'node:http';
@@ -1,7 +1,12 @@
1
+ export interface AuthenticateWithSessionOptions {
2
+ cookiePassword?: string;
3
+ sealSession: boolean;
4
+ }
1
5
  export interface AuthenticateWithOptionsBase {
2
6
  clientId: string;
3
7
  ipAddress?: string;
4
8
  userAgent?: string;
9
+ session?: AuthenticateWithSessionOptions;
5
10
  }
6
11
  export interface SerializedAuthenticateWithOptionsBase {
7
12
  client_id: string;
@@ -0,0 +1,24 @@
1
+ import { AuthenticationResponse } from './authentication-response.interface';
2
+ export interface AccessToken {
3
+ sid: string;
4
+ org_id?: string;
5
+ role?: string;
6
+ permissions?: string[];
7
+ }
8
+ export type SessionCookieData = Pick<AuthenticationResponse, 'accessToken' | 'impersonator' | 'organizationId' | 'refreshToken' | 'user'>;
9
+ export declare enum AuthenticateWithSessionCookieFailureReason {
10
+ INVALID_JWT = "invalid_jwt",
11
+ INVALID_SESSION_COOKIE = "invalid_session_cookie",
12
+ NO_SESSION_COOKIE_PROVIDED = "no_session_cookie_provided"
13
+ }
14
+ export type AuthenticateWithSessionCookieFailedResponse = {
15
+ authenticated: false;
16
+ reason: AuthenticateWithSessionCookieFailureReason;
17
+ };
18
+ export type AuthenticateWithSessionCookieSuccessResponse = {
19
+ authenticated: true;
20
+ sessionId: string;
21
+ organizationId?: string;
22
+ role?: string;
23
+ permissions?: string[];
24
+ };
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AuthenticateWithSessionCookieFailureReason = void 0;
4
+ var AuthenticateWithSessionCookieFailureReason;
5
+ (function (AuthenticateWithSessionCookieFailureReason) {
6
+ AuthenticateWithSessionCookieFailureReason["INVALID_JWT"] = "invalid_jwt";
7
+ AuthenticateWithSessionCookieFailureReason["INVALID_SESSION_COOKIE"] = "invalid_session_cookie";
8
+ AuthenticateWithSessionCookieFailureReason["NO_SESSION_COOKIE_PROVIDED"] = "no_session_cookie_provided";
9
+ })(AuthenticateWithSessionCookieFailureReason || (exports.AuthenticateWithSessionCookieFailureReason = AuthenticateWithSessionCookieFailureReason = {}));
@@ -8,6 +8,7 @@ export interface AuthenticationResponse {
8
8
  refreshToken: string;
9
9
  impersonator?: Impersonator;
10
10
  authenticationMethod?: AuthenticationMethod;
11
+ sealedSession?: string;
11
12
  }
12
13
  export interface AuthenticationResponseResponse {
13
14
  user: UserResponse;
@@ -7,6 +7,7 @@ export * from './authenticate-with-options-base.interface';
7
7
  export * from './authenticate-with-organization-selection.interface';
8
8
  export * from './authenticate-with-password-options.interface';
9
9
  export * from './authenticate-with-refresh-token-options.interface';
10
+ export * from './authenticate-with-session-cookie.interface';
10
11
  export * from './authenticate-with-totp-options.interface';
11
12
  export * from './authentication-response.interface';
12
13
  export * from './create-magic-auth-options.interface';
@@ -25,6 +26,7 @@ export * from './list-users-options.interface';
25
26
  export * from './magic-auth.interface';
26
27
  export * from './organization-membership.interface';
27
28
  export * from './password-reset.interface';
29
+ export * from './refresh-and-seal-session-data.interface';
28
30
  export * from './reset-password-options.interface';
29
31
  export * from './revoke-session-options.interface';
30
32
  export * from './send-invitation-options.interface';
@@ -23,6 +23,7 @@ __exportStar(require("./authenticate-with-options-base.interface"), exports);
23
23
  __exportStar(require("./authenticate-with-organization-selection.interface"), exports);
24
24
  __exportStar(require("./authenticate-with-password-options.interface"), exports);
25
25
  __exportStar(require("./authenticate-with-refresh-token-options.interface"), exports);
26
+ __exportStar(require("./authenticate-with-session-cookie.interface"), exports);
26
27
  __exportStar(require("./authenticate-with-totp-options.interface"), exports);
27
28
  __exportStar(require("./authentication-response.interface"), exports);
28
29
  __exportStar(require("./create-magic-auth-options.interface"), exports);
@@ -41,6 +42,7 @@ __exportStar(require("./list-users-options.interface"), exports);
41
42
  __exportStar(require("./magic-auth.interface"), exports);
42
43
  __exportStar(require("./organization-membership.interface"), exports);
43
44
  __exportStar(require("./password-reset.interface"), exports);
45
+ __exportStar(require("./refresh-and-seal-session-data.interface"), exports);
44
46
  __exportStar(require("./reset-password-options.interface"), exports);
45
47
  __exportStar(require("./revoke-session-options.interface"), exports);
46
48
  __exportStar(require("./send-invitation-options.interface"), exports);
@@ -0,0 +1,16 @@
1
+ export declare enum RefreshAndSealSessionDataFailureReason {
2
+ INVALID_SESSION_COOKE = "invalid_session_cookie",
3
+ NO_SESSION_COOKIE_PROVIDED = "no_session_cookie_provided",
4
+ INVALID_GRANT = "invalid_grant",
5
+ ORGANIZATION_NOT_AUTHORIZED = "organization_not_authorized"
6
+ }
7
+ type RefreshAndSealSessionDataFailedResponse = {
8
+ authenticated: false;
9
+ reason: RefreshAndSealSessionDataFailureReason;
10
+ };
11
+ type RefreshAndSealSessionDataSuccessResponse = {
12
+ authenticated: true;
13
+ sealedSession: string;
14
+ };
15
+ export type RefreshAndSealSessionDataResponse = RefreshAndSealSessionDataFailedResponse | RefreshAndSealSessionDataSuccessResponse;
16
+ export {};
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RefreshAndSealSessionDataFailureReason = void 0;
4
+ var RefreshAndSealSessionDataFailureReason;
5
+ (function (RefreshAndSealSessionDataFailureReason) {
6
+ RefreshAndSealSessionDataFailureReason["INVALID_SESSION_COOKE"] = "invalid_session_cookie";
7
+ RefreshAndSealSessionDataFailureReason["NO_SESSION_COOKIE_PROVIDED"] = "no_session_cookie_provided";
8
+ // API OauthErrors for refresh tokens
9
+ RefreshAndSealSessionDataFailureReason["INVALID_GRANT"] = "invalid_grant";
10
+ RefreshAndSealSessionDataFailureReason["ORGANIZATION_NOT_AUTHORIZED"] = "organization_not_authorized";
11
+ })(RefreshAndSealSessionDataFailureReason || (exports.RefreshAndSealSessionDataFailureReason = RefreshAndSealSessionDataFailureReason = {}));
@@ -0,0 +1,4 @@
1
+ export interface SessionHandlerOptions {
2
+ sessionData: string;
3
+ cookiePassword?: string;
4
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,22 +1,26 @@
1
- import { WorkOS } from '../workos';
2
1
  import { AutoPaginatable } from '../common/utils/pagination';
3
- import { AuthenticateWithCodeOptions, AuthenticateWithMagicAuthOptions, AuthenticateWithPasswordOptions, AuthenticateWithTotpOptions, AuthenticationResponse, ResetPasswordOptions, SendPasswordResetEmailOptions, CreateUserOptions, EnrollAuthFactorOptions, ListAuthFactorsOptions, ListUsersOptions, SendMagicAuthCodeOptions, SendVerificationEmailOptions, UpdateUserOptions, User, VerifyEmailOptions, AuthenticateWithRefreshTokenOptions, MagicAuth, CreateMagicAuthOptions, EmailVerification, PasswordReset, CreatePasswordResetOptions } from './interfaces';
4
2
  import { Challenge } from '../mfa/interfaces';
5
- import { OrganizationMembership } from './interfaces/organization-membership.interface';
6
- import { ListOrganizationMembershipsOptions } from './interfaces/list-organization-memberships-options.interface';
7
- import { CreateOrganizationMembershipOptions } from './interfaces/create-organization-membership-options.interface';
8
- import { Invitation } from './interfaces/invitation.interface';
9
- import { ListInvitationsOptions } from './interfaces/list-invitations-options.interface';
10
- import { SendInvitationOptions } from './interfaces/send-invitation-options.interface';
11
- import { AuthorizationURLOptions } from './interfaces/authorization-url-options.interface';
3
+ import { WorkOS } from '../workos';
4
+ import { AuthenticateWithCodeOptions, AuthenticateWithMagicAuthOptions, AuthenticateWithPasswordOptions, AuthenticateWithRefreshTokenOptions, AuthenticateWithTotpOptions, AuthenticationResponse, CreateMagicAuthOptions, CreatePasswordResetOptions, CreateUserOptions, EmailVerification, EnrollAuthFactorOptions, ListAuthFactorsOptions, ListUsersOptions, MagicAuth, PasswordReset, ResetPasswordOptions, SendMagicAuthCodeOptions, SendPasswordResetEmailOptions, SendVerificationEmailOptions, UpdateUserOptions, User, VerifyEmailOptions } from './interfaces';
12
5
  import { AuthenticateWithEmailVerificationOptions } from './interfaces/authenticate-with-email-verification-options.interface';
13
6
  import { AuthenticateWithOrganizationSelectionOptions } from './interfaces/authenticate-with-organization-selection.interface';
7
+ import { AuthenticateWithSessionCookieFailedResponse, AuthenticateWithSessionCookieSuccessResponse, SessionCookieData } from './interfaces/authenticate-with-session-cookie.interface';
8
+ import { AuthorizationURLOptions } from './interfaces/authorization-url-options.interface';
9
+ import { CreateOrganizationMembershipOptions } from './interfaces/create-organization-membership-options.interface';
14
10
  import { Factor, FactorWithSecrets } from './interfaces/factor.interface';
11
+ import { Identity } from './interfaces/identity.interface';
12
+ import { Invitation } from './interfaces/invitation.interface';
13
+ import { ListInvitationsOptions } from './interfaces/list-invitations-options.interface';
14
+ import { ListOrganizationMembershipsOptions } from './interfaces/list-organization-memberships-options.interface';
15
+ import { OrganizationMembership } from './interfaces/organization-membership.interface';
16
+ import { RefreshAndSealSessionDataResponse } from './interfaces/refresh-and-seal-session-data.interface';
15
17
  import { RevokeSessionOptions } from './interfaces/revoke-session-options.interface';
18
+ import { SendInvitationOptions } from './interfaces/send-invitation-options.interface';
19
+ import { SessionHandlerOptions } from './interfaces/session-handler-options.interface';
16
20
  import { UpdateOrganizationMembershipOptions } from './interfaces/update-organization-membership-options.interface';
17
- import { Identity } from './interfaces/identity.interface';
18
21
  export declare class UserManagement {
19
22
  private readonly workos;
23
+ private jwks;
20
24
  constructor(workos: WorkOS);
21
25
  getUser(userId: string): Promise<User>;
22
26
  listUsers(options?: ListUsersOptions): Promise<AutoPaginatable<User>>;
@@ -28,6 +32,12 @@ export declare class UserManagement {
28
32
  authenticateWithTotp(payload: AuthenticateWithTotpOptions): Promise<AuthenticationResponse>;
29
33
  authenticateWithEmailVerification(payload: AuthenticateWithEmailVerificationOptions): Promise<AuthenticationResponse>;
30
34
  authenticateWithOrganizationSelection(payload: AuthenticateWithOrganizationSelectionOptions): Promise<AuthenticationResponse>;
35
+ authenticateWithSessionCookie({ sessionData, cookiePassword, }: SessionHandlerOptions): Promise<AuthenticateWithSessionCookieSuccessResponse | AuthenticateWithSessionCookieFailedResponse>;
36
+ private isValidJwt;
37
+ refreshAndSealSessionData({ sessionData, cookiePassword, }: SessionHandlerOptions): Promise<RefreshAndSealSessionDataResponse>;
38
+ private prepareAuthenticationResponse;
39
+ private sealSessionDataFromAuthenticationResponse;
40
+ getSessionFromCookie({ sessionData, cookiePassword, }: SessionHandlerOptions): Promise<SessionCookieData | undefined>;
31
41
  getEmailVerification(emailVerificationId: string): Promise<EmailVerification>;
32
42
  sendVerificationEmail({ userId, }: SendVerificationEmailOptions): Promise<{
33
43
  user: User;
@@ -21,23 +21,28 @@ var __rest = (this && this.__rest) || function (s, e) {
21
21
  };
22
22
  Object.defineProperty(exports, "__esModule", { value: true });
23
23
  exports.UserManagement = void 0;
24
- const pagination_1 = require("../common/utils/pagination");
25
- const serializers_1 = require("./serializers");
24
+ const iron_session_1 = require("iron-session");
25
+ const jose_1 = require("jose");
26
+ const oauth_exception_1 = require("../common/exceptions/oauth.exception");
26
27
  const fetch_and_deserialize_1 = require("../common/utils/fetch-and-deserialize");
27
- const serializers_2 = require("../mfa/serializers");
28
- const organization_membership_serializer_1 = require("./serializers/organization-membership.serializer");
29
- const list_organization_memberships_options_serializer_1 = require("./serializers/list-organization-memberships-options.serializer");
28
+ const pagination_1 = require("../common/utils/pagination");
29
+ const serializers_1 = require("../mfa/serializers");
30
+ const authenticate_with_session_cookie_interface_1 = require("./interfaces/authenticate-with-session-cookie.interface");
31
+ const refresh_and_seal_session_data_interface_1 = require("./interfaces/refresh-and-seal-session-data.interface");
32
+ const revoke_session_options_interface_1 = require("./interfaces/revoke-session-options.interface");
33
+ const serializers_2 = require("./serializers");
34
+ const authenticate_with_email_verification_serializer_1 = require("./serializers/authenticate-with-email-verification.serializer");
35
+ const authenticate_with_organization_selection_options_serializer_1 = require("./serializers/authenticate-with-organization-selection-options.serializer");
30
36
  const create_organization_membership_options_serializer_1 = require("./serializers/create-organization-membership-options.serializer");
37
+ const factor_serializer_1 = require("./serializers/factor.serializer");
38
+ const identity_serializer_1 = require("./serializers/identity.serializer");
31
39
  const invitation_serializer_1 = require("./serializers/invitation.serializer");
32
40
  const list_invitations_options_serializer_1 = require("./serializers/list-invitations-options.serializer");
33
- const send_invitation_options_serializer_1 = require("./serializers/send-invitation-options.serializer");
41
+ const list_organization_memberships_options_serializer_1 = require("./serializers/list-organization-memberships-options.serializer");
34
42
  const list_users_options_serializer_1 = require("./serializers/list-users-options.serializer");
35
- const authenticate_with_email_verification_serializer_1 = require("./serializers/authenticate-with-email-verification.serializer");
36
- const authenticate_with_organization_selection_options_serializer_1 = require("./serializers/authenticate-with-organization-selection-options.serializer");
37
- const factor_serializer_1 = require("./serializers/factor.serializer");
38
- const revoke_session_options_interface_1 = require("./interfaces/revoke-session-options.interface");
43
+ const organization_membership_serializer_1 = require("./serializers/organization-membership.serializer");
44
+ const send_invitation_options_serializer_1 = require("./serializers/send-invitation-options.serializer");
39
45
  const update_organization_membership_options_serializer_1 = require("./serializers/update-organization-membership-options.serializer");
40
- const identity_serializer_1 = require("./serializers/identity.serializer");
41
46
  const toQueryString = (options) => {
42
47
  const searchParams = new URLSearchParams();
43
48
  const keys = Object.keys(options).sort();
@@ -52,88 +57,261 @@ const toQueryString = (options) => {
52
57
  class UserManagement {
53
58
  constructor(workos) {
54
59
  this.workos = workos;
60
+ const { clientId } = workos.options;
61
+ // Set the JWKS URL. This is used to verify if the JWT is still valid
62
+ this.jwks = clientId
63
+ ? (0, jose_1.createRemoteJWKSet)(new URL(this.getJwksUrl(clientId)))
64
+ : undefined;
55
65
  }
56
66
  getUser(userId) {
57
67
  return __awaiter(this, void 0, void 0, function* () {
58
68
  const { data } = yield this.workos.get(`/user_management/users/${userId}`);
59
- return (0, serializers_1.deserializeUser)(data);
69
+ return (0, serializers_2.deserializeUser)(data);
60
70
  });
61
71
  }
62
72
  listUsers(options) {
63
73
  return __awaiter(this, void 0, void 0, function* () {
64
- return new pagination_1.AutoPaginatable(yield (0, fetch_and_deserialize_1.fetchAndDeserialize)(this.workos, '/user_management/users', serializers_1.deserializeUser, options ? (0, list_users_options_serializer_1.serializeListUsersOptions)(options) : undefined), (params) => (0, fetch_and_deserialize_1.fetchAndDeserialize)(this.workos, '/user_management/users', serializers_1.deserializeUser, params), options ? (0, list_users_options_serializer_1.serializeListUsersOptions)(options) : undefined);
74
+ return new pagination_1.AutoPaginatable(yield (0, fetch_and_deserialize_1.fetchAndDeserialize)(this.workos, '/user_management/users', serializers_2.deserializeUser, options ? (0, list_users_options_serializer_1.serializeListUsersOptions)(options) : undefined), (params) => (0, fetch_and_deserialize_1.fetchAndDeserialize)(this.workos, '/user_management/users', serializers_2.deserializeUser, params), options ? (0, list_users_options_serializer_1.serializeListUsersOptions)(options) : undefined);
65
75
  });
66
76
  }
67
77
  createUser(payload) {
68
78
  return __awaiter(this, void 0, void 0, function* () {
69
- const { data } = yield this.workos.post('/user_management/users', (0, serializers_1.serializeCreateUserOptions)(payload));
70
- return (0, serializers_1.deserializeUser)(data);
79
+ const { data } = yield this.workos.post('/user_management/users', (0, serializers_2.serializeCreateUserOptions)(payload));
80
+ return (0, serializers_2.deserializeUser)(data);
71
81
  });
72
82
  }
73
83
  authenticateWithMagicAuth(payload) {
74
84
  return __awaiter(this, void 0, void 0, function* () {
75
- const { data } = yield this.workos.post('/user_management/authenticate', (0, serializers_1.serializeAuthenticateWithMagicAuthOptions)(Object.assign(Object.assign({}, payload), { clientSecret: this.workos.key })));
76
- return (0, serializers_1.deserializeAuthenticationResponse)(data);
85
+ const { session } = payload, remainingPayload = __rest(payload, ["session"]);
86
+ const { data } = yield this.workos.post('/user_management/authenticate', (0, serializers_2.serializeAuthenticateWithMagicAuthOptions)(Object.assign(Object.assign({}, remainingPayload), { clientSecret: this.workos.key })));
87
+ return this.prepareAuthenticationResponse({
88
+ authenticationResponse: (0, serializers_2.deserializeAuthenticationResponse)(data),
89
+ session,
90
+ });
77
91
  });
78
92
  }
79
93
  authenticateWithPassword(payload) {
80
94
  return __awaiter(this, void 0, void 0, function* () {
81
- const { data } = yield this.workos.post('/user_management/authenticate', (0, serializers_1.serializeAuthenticateWithPasswordOptions)(Object.assign(Object.assign({}, payload), { clientSecret: this.workos.key })));
82
- return (0, serializers_1.deserializeAuthenticationResponse)(data);
95
+ const { session } = payload, remainingPayload = __rest(payload, ["session"]);
96
+ const { data } = yield this.workos.post('/user_management/authenticate', (0, serializers_2.serializeAuthenticateWithPasswordOptions)(Object.assign(Object.assign({}, remainingPayload), { clientSecret: this.workos.key })));
97
+ return this.prepareAuthenticationResponse({
98
+ authenticationResponse: (0, serializers_2.deserializeAuthenticationResponse)(data),
99
+ session,
100
+ });
83
101
  });
84
102
  }
85
103
  authenticateWithCode(payload) {
86
104
  return __awaiter(this, void 0, void 0, function* () {
87
- const { data } = yield this.workos.post('/user_management/authenticate', (0, serializers_1.serializeAuthenticateWithCodeOptions)(Object.assign(Object.assign({}, payload), { clientSecret: this.workos.key })));
88
- return (0, serializers_1.deserializeAuthenticationResponse)(data);
105
+ const { session } = payload, remainingPayload = __rest(payload, ["session"]);
106
+ const { data } = yield this.workos.post('/user_management/authenticate', (0, serializers_2.serializeAuthenticateWithCodeOptions)(Object.assign(Object.assign({}, remainingPayload), { clientSecret: this.workos.key })));
107
+ return this.prepareAuthenticationResponse({
108
+ authenticationResponse: (0, serializers_2.deserializeAuthenticationResponse)(data),
109
+ session,
110
+ });
89
111
  });
90
112
  }
91
113
  authenticateWithRefreshToken(payload) {
92
114
  return __awaiter(this, void 0, void 0, function* () {
93
- const { data } = yield this.workos.post('/user_management/authenticate', (0, serializers_1.serializeAuthenticateWithRefreshTokenOptions)(Object.assign(Object.assign({}, payload), { clientSecret: this.workos.key })));
94
- return (0, serializers_1.deserializeAuthenticationResponse)(data);
115
+ const { session } = payload, remainingPayload = __rest(payload, ["session"]);
116
+ const { data } = yield this.workos.post('/user_management/authenticate', (0, serializers_2.serializeAuthenticateWithRefreshTokenOptions)(Object.assign(Object.assign({}, remainingPayload), { clientSecret: this.workos.key })));
117
+ return this.prepareAuthenticationResponse({
118
+ authenticationResponse: (0, serializers_2.deserializeAuthenticationResponse)(data),
119
+ session,
120
+ });
95
121
  });
96
122
  }
97
123
  authenticateWithTotp(payload) {
98
124
  return __awaiter(this, void 0, void 0, function* () {
99
- const { data } = yield this.workos.post('/user_management/authenticate', (0, serializers_1.serializeAuthenticateWithTotpOptions)(Object.assign(Object.assign({}, payload), { clientSecret: this.workos.key })));
100
- return (0, serializers_1.deserializeAuthenticationResponse)(data);
125
+ const { session } = payload, remainingPayload = __rest(payload, ["session"]);
126
+ const { data } = yield this.workos.post('/user_management/authenticate', (0, serializers_2.serializeAuthenticateWithTotpOptions)(Object.assign(Object.assign({}, remainingPayload), { clientSecret: this.workos.key })));
127
+ return this.prepareAuthenticationResponse({
128
+ authenticationResponse: (0, serializers_2.deserializeAuthenticationResponse)(data),
129
+ session,
130
+ });
101
131
  });
102
132
  }
103
133
  authenticateWithEmailVerification(payload) {
104
134
  return __awaiter(this, void 0, void 0, function* () {
105
- const { data } = yield this.workos.post('/user_management/authenticate', (0, authenticate_with_email_verification_serializer_1.serializeAuthenticateWithEmailVerificationOptions)(Object.assign(Object.assign({}, payload), { clientSecret: this.workos.key })));
106
- return (0, serializers_1.deserializeAuthenticationResponse)(data);
135
+ const { session } = payload, remainingPayload = __rest(payload, ["session"]);
136
+ const { data } = yield this.workos.post('/user_management/authenticate', (0, authenticate_with_email_verification_serializer_1.serializeAuthenticateWithEmailVerificationOptions)(Object.assign(Object.assign({}, remainingPayload), { clientSecret: this.workos.key })));
137
+ return this.prepareAuthenticationResponse({
138
+ authenticationResponse: (0, serializers_2.deserializeAuthenticationResponse)(data),
139
+ session,
140
+ });
107
141
  });
108
142
  }
109
143
  authenticateWithOrganizationSelection(payload) {
110
144
  return __awaiter(this, void 0, void 0, function* () {
111
- const { data } = yield this.workos.post('/user_management/authenticate', (0, authenticate_with_organization_selection_options_serializer_1.serializeAuthenticateWithOrganizationSelectionOptions)(Object.assign(Object.assign({}, payload), { clientSecret: this.workos.key })));
112
- return (0, serializers_1.deserializeAuthenticationResponse)(data);
145
+ const { session } = payload, remainingPayload = __rest(payload, ["session"]);
146
+ const { data } = yield this.workos.post('/user_management/authenticate', (0, authenticate_with_organization_selection_options_serializer_1.serializeAuthenticateWithOrganizationSelectionOptions)(Object.assign(Object.assign({}, remainingPayload), { clientSecret: this.workos.key })));
147
+ return this.prepareAuthenticationResponse({
148
+ authenticationResponse: (0, serializers_2.deserializeAuthenticationResponse)(data),
149
+ session,
150
+ });
151
+ });
152
+ }
153
+ authenticateWithSessionCookie({ sessionData, cookiePassword = process.env.WORKOS_COOKIE_PASSWORD, }) {
154
+ return __awaiter(this, void 0, void 0, function* () {
155
+ if (!cookiePassword) {
156
+ throw new Error('Cookie password is required');
157
+ }
158
+ if (!this.jwks) {
159
+ throw new Error('Must provide clientId to initialize JWKS');
160
+ }
161
+ if (!sessionData) {
162
+ return {
163
+ authenticated: false,
164
+ reason: authenticate_with_session_cookie_interface_1.AuthenticateWithSessionCookieFailureReason.NO_SESSION_COOKIE_PROVIDED,
165
+ };
166
+ }
167
+ const session = yield (0, iron_session_1.unsealData)(sessionData, {
168
+ password: cookiePassword,
169
+ });
170
+ if (!session.accessToken) {
171
+ return {
172
+ authenticated: false,
173
+ reason: authenticate_with_session_cookie_interface_1.AuthenticateWithSessionCookieFailureReason.INVALID_SESSION_COOKIE,
174
+ };
175
+ }
176
+ if (!(yield this.isValidJwt(session.accessToken))) {
177
+ return {
178
+ authenticated: false,
179
+ reason: authenticate_with_session_cookie_interface_1.AuthenticateWithSessionCookieFailureReason.INVALID_JWT,
180
+ };
181
+ }
182
+ const { sid: sessionId, org_id: organizationId, role, permissions, } = (0, jose_1.decodeJwt)(session.accessToken);
183
+ return {
184
+ authenticated: true,
185
+ sessionId,
186
+ organizationId,
187
+ role,
188
+ permissions,
189
+ };
190
+ });
191
+ }
192
+ isValidJwt(accessToken) {
193
+ return __awaiter(this, void 0, void 0, function* () {
194
+ if (!this.jwks) {
195
+ throw new Error('Must provide clientId to initialize JWKS');
196
+ }
197
+ try {
198
+ yield (0, jose_1.jwtVerify)(accessToken, this.jwks);
199
+ return true;
200
+ }
201
+ catch (e) {
202
+ return false;
203
+ }
204
+ });
205
+ }
206
+ refreshAndSealSessionData({ sessionData, cookiePassword = process.env.WORKOS_COOKIE_PASSWORD, }) {
207
+ return __awaiter(this, void 0, void 0, function* () {
208
+ if (!cookiePassword) {
209
+ throw new Error('Cookie password is required');
210
+ }
211
+ if (!sessionData) {
212
+ return {
213
+ authenticated: false,
214
+ reason: refresh_and_seal_session_data_interface_1.RefreshAndSealSessionDataFailureReason.NO_SESSION_COOKIE_PROVIDED,
215
+ };
216
+ }
217
+ const session = yield (0, iron_session_1.unsealData)(sessionData, {
218
+ password: cookiePassword,
219
+ });
220
+ if (!session.refreshToken || !session.user) {
221
+ return {
222
+ authenticated: false,
223
+ reason: refresh_and_seal_session_data_interface_1.RefreshAndSealSessionDataFailureReason.INVALID_SESSION_COOKE,
224
+ };
225
+ }
226
+ try {
227
+ const { sealedSession } = yield this.authenticateWithRefreshToken({
228
+ clientId: this.workos.clientId,
229
+ refreshToken: session.refreshToken,
230
+ session: { sealSession: true, cookiePassword },
231
+ });
232
+ if (!sealedSession) {
233
+ return {
234
+ authenticated: false,
235
+ reason: refresh_and_seal_session_data_interface_1.RefreshAndSealSessionDataFailureReason.INVALID_SESSION_COOKE,
236
+ };
237
+ }
238
+ return { authenticated: true, sealedSession };
239
+ }
240
+ catch (error) {
241
+ if (error instanceof oauth_exception_1.OauthException &&
242
+ // TODO: Add additional known errors and remove re-throw
243
+ (error.error === refresh_and_seal_session_data_interface_1.RefreshAndSealSessionDataFailureReason.INVALID_GRANT ||
244
+ error.error ===
245
+ refresh_and_seal_session_data_interface_1.RefreshAndSealSessionDataFailureReason.ORGANIZATION_NOT_AUTHORIZED)) {
246
+ return {
247
+ authenticated: false,
248
+ reason: error.error,
249
+ };
250
+ }
251
+ throw error;
252
+ }
253
+ });
254
+ }
255
+ prepareAuthenticationResponse({ authenticationResponse, session, }) {
256
+ return __awaiter(this, void 0, void 0, function* () {
257
+ if (session) {
258
+ return Object.assign(Object.assign({}, authenticationResponse), { sealedSession: yield this.sealSessionDataFromAuthenticationResponse({
259
+ authenticationResponse,
260
+ cookiePassword: session.cookiePassword,
261
+ }) });
262
+ }
263
+ return authenticationResponse;
264
+ });
265
+ }
266
+ sealSessionDataFromAuthenticationResponse({ authenticationResponse, cookiePassword, }) {
267
+ return __awaiter(this, void 0, void 0, function* () {
268
+ if (!cookiePassword) {
269
+ throw new Error('Cookie password is required');
270
+ }
271
+ const sessionData = {
272
+ user: authenticationResponse.user,
273
+ accessToken: authenticationResponse.accessToken,
274
+ refreshToken: authenticationResponse.refreshToken,
275
+ impersonator: authenticationResponse.impersonator,
276
+ };
277
+ return (0, iron_session_1.sealData)(sessionData, { password: cookiePassword });
278
+ });
279
+ }
280
+ getSessionFromCookie({ sessionData, cookiePassword = process.env.WORKOS_COOKIE_PASSWORD, }) {
281
+ return __awaiter(this, void 0, void 0, function* () {
282
+ if (!cookiePassword) {
283
+ throw new Error('Cookie password is required');
284
+ }
285
+ if (sessionData) {
286
+ return (0, iron_session_1.unsealData)(sessionData, {
287
+ password: cookiePassword,
288
+ });
289
+ }
290
+ return undefined;
113
291
  });
114
292
  }
115
293
  getEmailVerification(emailVerificationId) {
116
294
  return __awaiter(this, void 0, void 0, function* () {
117
295
  const { data } = yield this.workos.get(`/user_management/email_verification/${emailVerificationId}`);
118
- return (0, serializers_1.deserializeEmailVerification)(data);
296
+ return (0, serializers_2.deserializeEmailVerification)(data);
119
297
  });
120
298
  }
121
299
  sendVerificationEmail({ userId, }) {
122
300
  return __awaiter(this, void 0, void 0, function* () {
123
301
  const { data } = yield this.workos.post(`/user_management/users/${userId}/email_verification/send`, {});
124
- return { user: (0, serializers_1.deserializeUser)(data.user) };
302
+ return { user: (0, serializers_2.deserializeUser)(data.user) };
125
303
  });
126
304
  }
127
305
  getMagicAuth(magicAuthId) {
128
306
  return __awaiter(this, void 0, void 0, function* () {
129
307
  const { data } = yield this.workos.get(`/user_management/magic_auth/${magicAuthId}`);
130
- return (0, serializers_1.deserializeMagicAuth)(data);
308
+ return (0, serializers_2.deserializeMagicAuth)(data);
131
309
  });
132
310
  }
133
311
  createMagicAuth(options) {
134
312
  return __awaiter(this, void 0, void 0, function* () {
135
- const { data } = yield this.workos.post('/user_management/magic_auth', (0, serializers_1.serializeCreateMagicAuthOptions)(Object.assign({}, options)));
136
- return (0, serializers_1.deserializeMagicAuth)(data);
313
+ const { data } = yield this.workos.post('/user_management/magic_auth', (0, serializers_2.serializeCreateMagicAuthOptions)(Object.assign({}, options)));
314
+ return (0, serializers_2.deserializeMagicAuth)(data);
137
315
  });
138
316
  }
139
317
  /**
@@ -141,7 +319,7 @@ class UserManagement {
141
319
  */
142
320
  sendMagicAuthCode(options) {
143
321
  return __awaiter(this, void 0, void 0, function* () {
144
- yield this.workos.post('/user_management/magic_auth/send', (0, serializers_1.serializeSendMagicAuthCodeOptions)(options));
322
+ yield this.workos.post('/user_management/magic_auth/send', (0, serializers_2.serializeSendMagicAuthCodeOptions)(options));
145
323
  });
146
324
  }
147
325
  verifyEmail({ code, userId, }) {
@@ -149,19 +327,19 @@ class UserManagement {
149
327
  const { data } = yield this.workos.post(`/user_management/users/${userId}/email_verification/confirm`, {
150
328
  code,
151
329
  });
152
- return { user: (0, serializers_1.deserializeUser)(data.user) };
330
+ return { user: (0, serializers_2.deserializeUser)(data.user) };
153
331
  });
154
332
  }
155
333
  getPasswordReset(passwordResetId) {
156
334
  return __awaiter(this, void 0, void 0, function* () {
157
335
  const { data } = yield this.workos.get(`/user_management/password_reset/${passwordResetId}`);
158
- return (0, serializers_1.deserializePasswordReset)(data);
336
+ return (0, serializers_2.deserializePasswordReset)(data);
159
337
  });
160
338
  }
161
339
  createPasswordReset(options) {
162
340
  return __awaiter(this, void 0, void 0, function* () {
163
- const { data } = yield this.workos.post('/user_management/password_reset', (0, serializers_1.serializeCreatePasswordResetOptions)(Object.assign({}, options)));
164
- return (0, serializers_1.deserializePasswordReset)(data);
341
+ const { data } = yield this.workos.post('/user_management/password_reset', (0, serializers_2.serializeCreatePasswordResetOptions)(Object.assign({}, options)));
342
+ return (0, serializers_2.deserializePasswordReset)(data);
165
343
  });
166
344
  }
167
345
  /**
@@ -169,27 +347,27 @@ class UserManagement {
169
347
  */
170
348
  sendPasswordResetEmail(payload) {
171
349
  return __awaiter(this, void 0, void 0, function* () {
172
- yield this.workos.post('/user_management/password_reset/send', (0, serializers_1.serializeSendPasswordResetEmailOptions)(payload));
350
+ yield this.workos.post('/user_management/password_reset/send', (0, serializers_2.serializeSendPasswordResetEmailOptions)(payload));
173
351
  });
174
352
  }
175
353
  resetPassword(payload) {
176
354
  return __awaiter(this, void 0, void 0, function* () {
177
- const { data } = yield this.workos.post('/user_management/password_reset/confirm', (0, serializers_1.serializeResetPasswordOptions)(payload));
178
- return { user: (0, serializers_1.deserializeUser)(data.user) };
355
+ const { data } = yield this.workos.post('/user_management/password_reset/confirm', (0, serializers_2.serializeResetPasswordOptions)(payload));
356
+ return { user: (0, serializers_2.deserializeUser)(data.user) };
179
357
  });
180
358
  }
181
359
  updateUser(payload) {
182
360
  return __awaiter(this, void 0, void 0, function* () {
183
- const { data } = yield this.workos.put(`/user_management/users/${payload.userId}`, (0, serializers_1.serializeUpdateUserOptions)(payload));
184
- return (0, serializers_1.deserializeUser)(data);
361
+ const { data } = yield this.workos.put(`/user_management/users/${payload.userId}`, (0, serializers_2.serializeUpdateUserOptions)(payload));
362
+ return (0, serializers_2.deserializeUser)(data);
185
363
  });
186
364
  }
187
365
  enrollAuthFactor(payload) {
188
366
  return __awaiter(this, void 0, void 0, function* () {
189
- const { data } = yield this.workos.post(`/user_management/users/${payload.userId}/auth_factors`, (0, serializers_1.serializeEnrollAuthFactorOptions)(payload));
367
+ const { data } = yield this.workos.post(`/user_management/users/${payload.userId}/auth_factors`, (0, serializers_2.serializeEnrollAuthFactorOptions)(payload));
190
368
  return {
191
- authenticationFactor: (0, serializers_1.deserializeFactorWithSecrets)(data.authentication_factor),
192
- authenticationChallenge: (0, serializers_2.deserializeChallenge)(data.authentication_challenge),
369
+ authenticationFactor: (0, serializers_2.deserializeFactorWithSecrets)(data.authentication_factor),
370
+ authenticationChallenge: (0, serializers_1.deserializeChallenge)(data.authentication_challenge),
193
371
  };
194
372
  });
195
373
  }
@@ -1,4 +1,27 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
26
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
27
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -27,7 +50,8 @@ const organization_membership_json_1 = __importDefault(require("./fixtures/organ
27
50
  const password_reset_json_1 = __importDefault(require("./fixtures/password_reset.json"));
28
51
  const user_json_1 = __importDefault(require("./fixtures/user.json"));
29
52
  const identity_json_1 = __importDefault(require("./fixtures/identity.json"));
30
- const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
53
+ const jose = __importStar(require("jose"));
54
+ const iron_session_1 = require("iron-session");
31
55
  const userId = 'user_01H5JQDV7R7ATEYZDEG0W5PRYS';
32
56
  const organizationMembershipId = 'om_01H5JQDV7R7ATEYZDEG0W5PRYS';
33
57
  const emailVerificationId = 'email_verification_01H5JQDV7R7ATEYZDEG0W5PRYS';
@@ -36,6 +60,13 @@ const invitationToken = 'Z1uX3RbwcIl5fIGJJJCXXisdI';
36
60
  const magicAuthId = 'magic_auth_01H5JQDV7R7ATEYZDEG0W5PRYS';
37
61
  const passwordResetId = 'password_reset_01H5JQDV7R7ATEYZDEG0W5PRYS';
38
62
  describe('UserManagement', () => {
63
+ let workos;
64
+ beforeAll(() => {
65
+ workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU', {
66
+ apiHostname: 'api.workos.test',
67
+ clientId: 'proj_123',
68
+ });
69
+ });
39
70
  beforeEach(() => jest_fetch_mock_1.default.resetMocks());
40
71
  describe('getUser', () => {
41
72
  it('sends a Get User request', () => __awaiter(void 0, void 0, void 0, function* () {
@@ -127,8 +158,45 @@ describe('UserManagement', () => {
127
158
  },
128
159
  });
129
160
  }));
161
+ describe('when sealSession = true', () => {
162
+ beforeEach(() => {
163
+ (0, test_utils_1.fetchOnce)({ user: user_json_1.default });
164
+ });
165
+ describe('when the cookie password is undefined', () => {
166
+ it('throws an error', () => __awaiter(void 0, void 0, void 0, function* () {
167
+ yield expect(workos.userManagement.authenticateWithMagicAuth({
168
+ clientId: 'proj_whatever',
169
+ code: '123456',
170
+ email: user_json_1.default.email,
171
+ session: { sealSession: true },
172
+ })).rejects.toThrow('Cookie password is required');
173
+ }));
174
+ });
175
+ describe('when successfully authenticated', () => {
176
+ it('returns the sealed session data', () => __awaiter(void 0, void 0, void 0, function* () {
177
+ const cookiePassword = 'alongcookiesecretmadefortestingsessions';
178
+ const response = yield workos.userManagement.authenticateWithMagicAuth({
179
+ clientId: 'proj_whatever',
180
+ code: '123456',
181
+ email: user_json_1.default.email,
182
+ session: { sealSession: true, cookiePassword },
183
+ });
184
+ expect(response).toEqual({
185
+ sealedSession: expect.any(String),
186
+ accessToken: undefined,
187
+ authenticationMethod: undefined,
188
+ impersonator: undefined,
189
+ organizationId: undefined,
190
+ refreshToken: undefined,
191
+ user: expect.objectContaining({
192
+ email: 'test01@example.com',
193
+ }),
194
+ });
195
+ }));
196
+ });
197
+ });
130
198
  });
131
- describe('authenticateUserWithPassword', () => {
199
+ describe('authenticateWithPassword', () => {
132
200
  it('sends an password authentication request', () => __awaiter(void 0, void 0, void 0, function* () {
133
201
  (0, test_utils_1.fetchOnce)({ user: user_json_1.default });
134
202
  const resp = yield workos.userManagement.authenticateWithPassword({
@@ -143,8 +211,45 @@ describe('UserManagement', () => {
143
211
  },
144
212
  });
145
213
  }));
214
+ describe('when sealSession = true', () => {
215
+ beforeEach(() => {
216
+ (0, test_utils_1.fetchOnce)({ user: user_json_1.default });
217
+ });
218
+ describe('when the cookie password is undefined', () => {
219
+ it('throws an error', () => __awaiter(void 0, void 0, void 0, function* () {
220
+ yield expect(workos.userManagement.authenticateWithPassword({
221
+ clientId: 'proj_whatever',
222
+ email: 'test01@example.com',
223
+ password: 'extra-secure',
224
+ session: { sealSession: true },
225
+ })).rejects.toThrow('Cookie password is required');
226
+ }));
227
+ });
228
+ describe('when successfully authenticated', () => {
229
+ it('returns the sealed session data', () => __awaiter(void 0, void 0, void 0, function* () {
230
+ const cookiePassword = 'alongcookiesecretmadefortestingsessions';
231
+ const response = yield workos.userManagement.authenticateWithPassword({
232
+ clientId: 'proj_whatever',
233
+ email: 'test01@example.com',
234
+ password: 'extra-secure',
235
+ session: { sealSession: true, cookiePassword },
236
+ });
237
+ expect(response).toEqual({
238
+ sealedSession: expect.any(String),
239
+ accessToken: undefined,
240
+ authenticationMethod: undefined,
241
+ impersonator: undefined,
242
+ organizationId: undefined,
243
+ refreshToken: undefined,
244
+ user: expect.objectContaining({
245
+ email: 'test01@example.com',
246
+ }),
247
+ });
248
+ }));
249
+ });
250
+ });
146
251
  });
147
- describe('authenticateUserWithCode', () => {
252
+ describe('authenticateWithCode', () => {
148
253
  it('sends a token authentication request', () => __awaiter(void 0, void 0, void 0, function* () {
149
254
  (0, test_utils_1.fetchOnce)({ user: user_json_1.default });
150
255
  const resp = yield workos.userManagement.authenticateWithCode({
@@ -225,6 +330,41 @@ describe('UserManagement', () => {
225
330
  });
226
331
  }));
227
332
  });
333
+ describe('when sealSession = true', () => {
334
+ beforeEach(() => {
335
+ (0, test_utils_1.fetchOnce)({ user: user_json_1.default });
336
+ });
337
+ describe('when the cookie password is undefined', () => {
338
+ it('throws an error', () => __awaiter(void 0, void 0, void 0, function* () {
339
+ yield expect(workos.userManagement.authenticateWithCode({
340
+ clientId: 'proj_whatever',
341
+ code: 'or this',
342
+ session: { sealSession: true },
343
+ })).rejects.toThrow('Cookie password is required');
344
+ }));
345
+ });
346
+ describe('when successfully authenticated', () => {
347
+ it('returns the sealed session data', () => __awaiter(void 0, void 0, void 0, function* () {
348
+ const cookiePassword = 'alongcookiesecretmadefortestingsessions';
349
+ const response = yield workos.userManagement.authenticateWithCode({
350
+ clientId: 'proj_whatever',
351
+ code: 'or this',
352
+ session: { sealSession: true, cookiePassword },
353
+ });
354
+ expect(response).toEqual({
355
+ sealedSession: expect.any(String),
356
+ accessToken: undefined,
357
+ authenticationMethod: undefined,
358
+ impersonator: undefined,
359
+ organizationId: undefined,
360
+ refreshToken: undefined,
361
+ user: expect.objectContaining({
362
+ email: 'test01@example.com',
363
+ }),
364
+ });
365
+ }));
366
+ });
367
+ });
228
368
  });
229
369
  describe('authenticateWithRefreshToken', () => {
230
370
  it('sends a refresh_token authentication request', () => __awaiter(void 0, void 0, void 0, function* () {
@@ -249,8 +389,43 @@ describe('UserManagement', () => {
249
389
  refreshToken: 'refreshToken2',
250
390
  });
251
391
  }));
392
+ describe('when sealSession = true', () => {
393
+ beforeEach(() => {
394
+ (0, test_utils_1.fetchOnce)({ user: user_json_1.default });
395
+ });
396
+ describe('when the cookie password is undefined', () => {
397
+ it('throws an error', () => __awaiter(void 0, void 0, void 0, function* () {
398
+ yield expect(workos.userManagement.authenticateWithRefreshToken({
399
+ clientId: 'proj_whatever',
400
+ refreshToken: 'refresh_token1',
401
+ session: { sealSession: true },
402
+ })).rejects.toThrow('Cookie password is required');
403
+ }));
404
+ });
405
+ describe('when successfully authenticated', () => {
406
+ it('returns the sealed session data', () => __awaiter(void 0, void 0, void 0, function* () {
407
+ const cookiePassword = 'alongcookiesecretmadefortestingsessions';
408
+ const response = yield workos.userManagement.authenticateWithRefreshToken({
409
+ clientId: 'proj_whatever',
410
+ refreshToken: 'refresh_token1',
411
+ session: { sealSession: true, cookiePassword },
412
+ });
413
+ expect(response).toEqual({
414
+ sealedSession: expect.any(String),
415
+ accessToken: undefined,
416
+ authenticationMethod: undefined,
417
+ impersonator: undefined,
418
+ organizationId: undefined,
419
+ refreshToken: undefined,
420
+ user: expect.objectContaining({
421
+ email: 'test01@example.com',
422
+ }),
423
+ });
424
+ }));
425
+ });
426
+ });
252
427
  });
253
- describe('authenticateUserWithTotp', () => {
428
+ describe('authenticateWithTotp', () => {
254
429
  it('sends a token authentication request', () => __awaiter(void 0, void 0, void 0, function* () {
255
430
  (0, test_utils_1.fetchOnce)({ user: user_json_1.default });
256
431
  const resp = yield workos.userManagement.authenticateWithTotp({
@@ -274,8 +449,47 @@ describe('UserManagement', () => {
274
449
  },
275
450
  });
276
451
  }));
452
+ describe('when sealSession = true', () => {
453
+ beforeEach(() => {
454
+ (0, test_utils_1.fetchOnce)({ user: user_json_1.default });
455
+ });
456
+ describe('when the cookie password is undefined', () => {
457
+ it('throws an error', () => __awaiter(void 0, void 0, void 0, function* () {
458
+ yield expect(workos.userManagement.authenticateWithTotp({
459
+ clientId: 'proj_whatever',
460
+ code: 'or this',
461
+ authenticationChallengeId: 'auth_challenge_01H96FETXGTW1QMBSBT2T36PW0',
462
+ pendingAuthenticationToken: 'cTDQJTTkTkkVYxQUlKBIxEsFs',
463
+ session: { sealSession: true },
464
+ })).rejects.toThrow('Cookie password is required');
465
+ }));
466
+ });
467
+ describe('when successfully authenticated', () => {
468
+ it('returns the sealed session data', () => __awaiter(void 0, void 0, void 0, function* () {
469
+ const cookiePassword = 'alongcookiesecretmadefortestingsessions';
470
+ const response = yield workos.userManagement.authenticateWithTotp({
471
+ clientId: 'proj_whatever',
472
+ code: 'or this',
473
+ authenticationChallengeId: 'auth_challenge_01H96FETXGTW1QMBSBT2T36PW0',
474
+ pendingAuthenticationToken: 'cTDQJTTkTkkVYxQUlKBIxEsFs',
475
+ session: { sealSession: true, cookiePassword },
476
+ });
477
+ expect(response).toEqual({
478
+ sealedSession: expect.any(String),
479
+ accessToken: undefined,
480
+ authenticationMethod: undefined,
481
+ impersonator: undefined,
482
+ organizationId: undefined,
483
+ refreshToken: undefined,
484
+ user: expect.objectContaining({
485
+ email: 'test01@example.com',
486
+ }),
487
+ });
488
+ }));
489
+ });
490
+ });
277
491
  });
278
- describe('authenticateUserWithEmailVerification', () => {
492
+ describe('authenticateWithEmailVerification', () => {
279
493
  it('sends an email verification authentication request', () => __awaiter(void 0, void 0, void 0, function* () {
280
494
  (0, test_utils_1.fetchOnce)({ user: user_json_1.default });
281
495
  const resp = yield workos.userManagement.authenticateWithEmailVerification({
@@ -297,6 +511,43 @@ describe('UserManagement', () => {
297
511
  },
298
512
  });
299
513
  }));
514
+ describe('when sealSession = true', () => {
515
+ beforeEach(() => {
516
+ (0, test_utils_1.fetchOnce)({ user: user_json_1.default });
517
+ });
518
+ describe('when the cookie password is undefined', () => {
519
+ it('throws an error', () => __awaiter(void 0, void 0, void 0, function* () {
520
+ yield expect(workos.userManagement.authenticateWithEmailVerification({
521
+ clientId: 'proj_whatever',
522
+ code: 'or this',
523
+ pendingAuthenticationToken: 'cTDQJTTkTkkVYxQUlKBIxEsFs',
524
+ session: { sealSession: true },
525
+ })).rejects.toThrow('Cookie password is required');
526
+ }));
527
+ });
528
+ describe('when successfully authenticated', () => {
529
+ it('returns the sealed session data', () => __awaiter(void 0, void 0, void 0, function* () {
530
+ const cookiePassword = 'alongcookiesecretmadefortestingsessions';
531
+ const response = yield workos.userManagement.authenticateWithEmailVerification({
532
+ clientId: 'proj_whatever',
533
+ code: 'or this',
534
+ pendingAuthenticationToken: 'cTDQJTTkTkkVYxQUlKBIxEsFs',
535
+ session: { sealSession: true, cookiePassword },
536
+ });
537
+ expect(response).toEqual({
538
+ sealedSession: expect.any(String),
539
+ accessToken: undefined,
540
+ authenticationMethod: undefined,
541
+ impersonator: undefined,
542
+ organizationId: undefined,
543
+ refreshToken: undefined,
544
+ user: expect.objectContaining({
545
+ email: 'test01@example.com',
546
+ }),
547
+ });
548
+ }));
549
+ });
550
+ });
300
551
  });
301
552
  describe('authenticateWithOrganizationSelection', () => {
302
553
  it('sends an Organization Selection Authentication request', () => __awaiter(void 0, void 0, void 0, function* () {
@@ -320,6 +571,253 @@ describe('UserManagement', () => {
320
571
  },
321
572
  });
322
573
  }));
574
+ describe('when sealSession = true', () => {
575
+ beforeEach(() => {
576
+ (0, test_utils_1.fetchOnce)({ user: user_json_1.default });
577
+ });
578
+ describe('when the cookie password is undefined', () => {
579
+ it('throws an error', () => __awaiter(void 0, void 0, void 0, function* () {
580
+ yield expect(workos.userManagement.authenticateWithOrganizationSelection({
581
+ clientId: 'proj_whatever',
582
+ pendingAuthenticationToken: 'cTDQJTTkTkkVYxQUlKBIxEsFs',
583
+ organizationId: 'org_01H5JQDV7R7ATEYZDEG0W5PRYS',
584
+ session: { sealSession: true },
585
+ })).rejects.toThrow('Cookie password is required');
586
+ }));
587
+ });
588
+ describe('when successfully authenticated', () => {
589
+ it('returns the sealed session data', () => __awaiter(void 0, void 0, void 0, function* () {
590
+ const cookiePassword = 'alongcookiesecretmadefortestingsessions';
591
+ const response = yield workos.userManagement.authenticateWithOrganizationSelection({
592
+ clientId: 'proj_whatever',
593
+ pendingAuthenticationToken: 'cTDQJTTkTkkVYxQUlKBIxEsFs',
594
+ organizationId: 'org_01H5JQDV7R7ATEYZDEG0W5PRYS',
595
+ session: { sealSession: true, cookiePassword },
596
+ });
597
+ expect(response).toEqual({
598
+ sealedSession: expect.any(String),
599
+ accessToken: undefined,
600
+ authenticationMethod: undefined,
601
+ impersonator: undefined,
602
+ organizationId: undefined,
603
+ refreshToken: undefined,
604
+ user: expect.objectContaining({
605
+ email: 'test01@example.com',
606
+ }),
607
+ });
608
+ }));
609
+ });
610
+ });
611
+ });
612
+ describe('authenticateWithSessionCookie', () => {
613
+ beforeEach(() => {
614
+ // Mock createRemoteJWKSet
615
+ jest
616
+ .spyOn(jose, 'createRemoteJWKSet')
617
+ .mockImplementation((_url, _options) => {
618
+ // This function simulates the token verification process
619
+ const verifyFunction = (_protectedHeader, _token) => {
620
+ return Promise.resolve({
621
+ type: 'public',
622
+ });
623
+ };
624
+ // Return an object that includes the verify function and the additional expected properties
625
+ return {
626
+ __call__: verifyFunction,
627
+ coolingDown: false,
628
+ fresh: false,
629
+ reloading: false,
630
+ reload: jest.fn().mockResolvedValue(undefined),
631
+ jwks: () => undefined,
632
+ };
633
+ });
634
+ });
635
+ it('throws an error when the cookie password is undefined', () => __awaiter(void 0, void 0, void 0, function* () {
636
+ yield expect(workos.userManagement.authenticateWithSessionCookie({
637
+ sessionData: 'session_cookie',
638
+ })).rejects.toThrow('Cookie password is required');
639
+ }));
640
+ it('returns authenticated = false when the session cookie is empty', () => __awaiter(void 0, void 0, void 0, function* () {
641
+ yield expect(workos.userManagement.authenticateWithSessionCookie({
642
+ sessionData: '',
643
+ cookiePassword: 'secret',
644
+ })).resolves.toEqual({
645
+ authenticated: false,
646
+ reason: 'no_session_cookie_provided',
647
+ });
648
+ }));
649
+ it('returns authenticated = false when session cookie is invalid', () => __awaiter(void 0, void 0, void 0, function* () {
650
+ yield expect(workos.userManagement.authenticateWithSessionCookie({
651
+ sessionData: 'thisisacookie',
652
+ cookiePassword: 'secret',
653
+ })).resolves.toEqual({
654
+ authenticated: false,
655
+ reason: 'invalid_session_cookie',
656
+ });
657
+ }));
658
+ it('returns authenticated = false when session cookie cannot be unsealed', () => __awaiter(void 0, void 0, void 0, function* () {
659
+ const cookiePassword = 'alongcookiesecretmadefortestingsessions';
660
+ const sessionData = yield (0, iron_session_1.sealData)({
661
+ accessToken: 'abc123',
662
+ refreshToken: 'def456',
663
+ user: {
664
+ object: 'user',
665
+ id: 'user_01H5JQDV7R7ATEYZDEG0W5PRYS',
666
+ email: 'test@example.com',
667
+ },
668
+ }, { password: cookiePassword });
669
+ yield expect(workos.userManagement.authenticateWithSessionCookie({
670
+ sessionData,
671
+ cookiePassword: 'secretpasswordwhichisalsolongbutnottherightone',
672
+ })).resolves.toEqual({
673
+ authenticated: false,
674
+ reason: 'invalid_session_cookie',
675
+ });
676
+ }));
677
+ it('returns authenticated = false when the JWT is invalid', () => __awaiter(void 0, void 0, void 0, function* () {
678
+ jest.spyOn(jose, 'jwtVerify').mockImplementationOnce(() => {
679
+ throw new Error('Invalid JWT');
680
+ });
681
+ const cookiePassword = 'alongcookiesecretmadefortestingsessions';
682
+ const sessionData = yield (0, iron_session_1.sealData)({
683
+ accessToken: 'abc123',
684
+ refreshToken: 'def456',
685
+ user: {
686
+ object: 'user',
687
+ id: 'user_01H5JQDV7R7ATEYZDEG0W5PRYS',
688
+ email: 'test@example.com',
689
+ },
690
+ }, { password: cookiePassword });
691
+ yield expect(workos.userManagement.authenticateWithSessionCookie({
692
+ sessionData,
693
+ cookiePassword,
694
+ })).resolves.toEqual({ authenticated: false, reason: 'invalid_jwt' });
695
+ }));
696
+ it('returns the JWT claims when provided a valid JWT', () => __awaiter(void 0, void 0, void 0, function* () {
697
+ jest
698
+ .spyOn(jose, 'jwtVerify')
699
+ .mockResolvedValue({});
700
+ const cookiePassword = 'alongcookiesecretmadefortestingsessions';
701
+ const sessionData = yield (0, iron_session_1.sealData)({
702
+ accessToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ewogICJzdWIiOiAiMTIzNDU2Nzg5MCIsCiAgIm5hbWUiOiAiSm9obiBEb2UiLAogICJpYXQiOiAxNTE2MjM5MDIyLAogICJzaWQiOiAic2Vzc2lvbl8xMjMiLAogICJvcmdfaWQiOiAib3JnXzEyMyIsCiAgInJvbGUiOiAibWVtYmVyIiwKICAicGVybWlzc2lvbnMiOiBbInBvc3RzOmNyZWF0ZSIsICJwb3N0czpkZWxldGUiXQp9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c',
703
+ refreshToken: 'def456',
704
+ user: {
705
+ object: 'user',
706
+ id: 'user_01H5JQDV7R7ATEYZDEG0W5PRYS',
707
+ email: 'test@example.com',
708
+ },
709
+ }, { password: cookiePassword });
710
+ yield expect(workos.userManagement.authenticateWithSessionCookie({
711
+ sessionData,
712
+ cookiePassword,
713
+ })).resolves.toEqual({
714
+ authenticated: true,
715
+ sessionId: 'session_123',
716
+ organizationId: 'org_123',
717
+ role: 'member',
718
+ permissions: ['posts:create', 'posts:delete'],
719
+ });
720
+ }));
721
+ });
722
+ describe('refreshAndSealSessionData', () => {
723
+ it('throws an error when the cookie password is undefined', () => __awaiter(void 0, void 0, void 0, function* () {
724
+ yield expect(workos.userManagement.refreshAndSealSessionData({
725
+ sessionData: 'session_cookie',
726
+ })).rejects.toThrow('Cookie password is required');
727
+ }));
728
+ it('returns authenticated = false when the session cookie is empty', () => __awaiter(void 0, void 0, void 0, function* () {
729
+ yield expect(workos.userManagement.refreshAndSealSessionData({
730
+ sessionData: '',
731
+ cookiePassword: 'secret',
732
+ })).resolves.toEqual({
733
+ authenticated: false,
734
+ reason: 'no_session_cookie_provided',
735
+ });
736
+ }));
737
+ it('returns authenticated = false when session cookie is invalid', () => __awaiter(void 0, void 0, void 0, function* () {
738
+ yield expect(workos.userManagement.refreshAndSealSessionData({
739
+ sessionData: 'thisisacookie',
740
+ cookiePassword: 'secret',
741
+ })).resolves.toEqual({
742
+ authenticated: false,
743
+ reason: 'invalid_session_cookie',
744
+ });
745
+ }));
746
+ it('returns authenticated = false when session cookie cannot be unsealed', () => __awaiter(void 0, void 0, void 0, function* () {
747
+ const cookiePassword = 'alongcookiesecretmadefortestingsessions';
748
+ const sessionData = yield (0, iron_session_1.sealData)({
749
+ accessToken: 'abc123',
750
+ refreshToken: 'def456',
751
+ user: {
752
+ object: 'user',
753
+ id: 'user_01H5JQDV7R7ATEYZDEG0W5PRYS',
754
+ email: 'test@example.com',
755
+ },
756
+ }, { password: cookiePassword });
757
+ yield expect(workos.userManagement.refreshAndSealSessionData({
758
+ sessionData,
759
+ cookiePassword: 'secretpasswordwhichisalsolongbutnottherightone',
760
+ })).resolves.toEqual({
761
+ authenticated: false,
762
+ reason: 'invalid_session_cookie',
763
+ });
764
+ }));
765
+ it('returns the sealed refreshed session cookie when provided a valid existing session cookie', () => __awaiter(void 0, void 0, void 0, function* () {
766
+ (0, test_utils_1.fetchOnce)({
767
+ user: user_json_1.default,
768
+ access_token: 'access_token',
769
+ refresh_token: 'refresh_token',
770
+ });
771
+ const cookiePassword = 'alongcookiesecretmadefortestingsessions';
772
+ const sessionData = yield (0, iron_session_1.sealData)({
773
+ accessToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ewogICJzdWIiOiAiMTIzNDU2Nzg5MCIsCiAgIm5hbWUiOiAiSm9obiBEb2UiLAogICJpYXQiOiAxNTE2MjM5MDIyLAogICJzaWQiOiAic2Vzc2lvbl8xMjMiLAogICJvcmdfaWQiOiAib3JnXzEyMyIsCiAgInJvbGUiOiAibWVtYmVyIiwKICAicGVybWlzc2lvbnMiOiBbInBvc3RzOmNyZWF0ZSIsICJwb3N0czpkZWxldGUiXQp9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c',
774
+ refreshToken: 'def456',
775
+ user: {
776
+ object: 'user',
777
+ id: 'user_01H5JQDV7R7ATEYZDEG0W5PRYS',
778
+ email: 'test@example.com',
779
+ },
780
+ }, { password: cookiePassword });
781
+ yield expect(workos.userManagement.refreshAndSealSessionData({
782
+ sessionData,
783
+ cookiePassword,
784
+ })).resolves.toEqual({
785
+ sealedSession: expect.any(String),
786
+ authenticated: true,
787
+ });
788
+ }));
789
+ });
790
+ describe('getSessionFromCookie', () => {
791
+ it('throws an error when the cookie password is undefined', () => __awaiter(void 0, void 0, void 0, function* () {
792
+ yield expect(workos.userManagement.getSessionFromCookie({
793
+ sessionData: 'session_cookie',
794
+ })).rejects.toThrow('Cookie password is required');
795
+ }));
796
+ it('returns undefined when the session cookie cannot be unsealed', () => __awaiter(void 0, void 0, void 0, function* () {
797
+ yield expect(workos.userManagement.getSessionFromCookie({
798
+ sessionData: '',
799
+ cookiePassword: 'secret',
800
+ })).resolves.toBeUndefined();
801
+ }));
802
+ it('returns the unsealed session cookie data when provided a valid session cookie', () => __awaiter(void 0, void 0, void 0, function* () {
803
+ const cookiePassword = 'alongcookiesecretmadefortestingsessions';
804
+ const sessionCookieData = {
805
+ accessToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ewogICJzdWIiOiAiMTIzNDU2Nzg5MCIsCiAgIm5hbWUiOiAiSm9obiBEb2UiLAogICJpYXQiOiAxNTE2MjM5MDIyLAogICJzaWQiOiAic2Vzc2lvbl8xMjMiLAogICJvcmdfaWQiOiAib3JnXzEyMyIsCiAgInJvbGUiOiAibWVtYmVyIiwKICAicGVybWlzc2lvbnMiOiBbInBvc3RzOmNyZWF0ZSIsICJwb3N0czpkZWxldGUiXQp9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c',
806
+ refreshToken: 'def456',
807
+ user: {
808
+ object: 'user',
809
+ id: 'user_01H5JQDV7R7ATEYZDEG0W5PRYS',
810
+ email: 'test@example.com',
811
+ },
812
+ };
813
+ const sessionData = yield (0, iron_session_1.sealData)(sessionCookieData, {
814
+ password: cookiePassword,
815
+ });
816
+ yield expect(workos.userManagement.getSessionFromCookie({
817
+ sessionData,
818
+ cookiePassword,
819
+ })).resolves.toEqual(sessionCookieData);
820
+ }));
323
821
  });
324
822
  describe('getEmailVerification', () => {
325
823
  it('sends a Get EmailVerification request', () => __awaiter(void 0, void 0, void 0, function* () {
package/lib/workos.d.ts CHANGED
@@ -16,6 +16,7 @@ export declare class WorkOS {
16
16
  readonly options: WorkOSOptions;
17
17
  readonly baseURL: string;
18
18
  readonly client: HttpClient;
19
+ readonly clientId?: string;
19
20
  readonly auditLogs: AuditLogs;
20
21
  readonly directorySync: DirectorySync;
21
22
  readonly organizations: Organizations;
package/lib/workos.js CHANGED
@@ -26,10 +26,11 @@ const bad_request_exception_1 = require("./common/exceptions/bad-request.excepti
26
26
  const http_client_1 = require("./common/net/http-client");
27
27
  const subtle_crypto_provider_1 = require("./common/crypto/subtle-crypto-provider");
28
28
  const fetch_client_1 = require("./common/net/fetch-client");
29
- const VERSION = '7.14.0';
29
+ const VERSION = '7.15.0';
30
30
  const DEFAULT_HOSTNAME = 'api.workos.com';
31
31
  class WorkOS {
32
32
  constructor(key, options = {}) {
33
+ var _a;
33
34
  this.key = key;
34
35
  this.options = options;
35
36
  this.auditLogs = new audit_logs_1.AuditLogs(this);
@@ -41,7 +42,6 @@ class WorkOS {
41
42
  this.sso = new sso_1.SSO(this);
42
43
  this.mfa = new mfa_1.Mfa(this);
43
44
  this.events = new events_1.Events(this);
44
- this.userManagement = new user_management_1.UserManagement(this);
45
45
  if (!key) {
46
46
  // process might be undefined in some environments
47
47
  this.key = process === null || process === void 0 ? void 0 : process.env.WORKOS_API_KEY;
@@ -52,6 +52,7 @@ class WorkOS {
52
52
  if (this.options.https === undefined) {
53
53
  this.options.https = true;
54
54
  }
55
+ this.clientId = (_a = this.options.clientId) !== null && _a !== void 0 ? _a : process === null || process === void 0 ? void 0 : process.env.WORKOS_CLIENT_ID;
55
56
  const protocol = this.options.https ? 'https' : 'http';
56
57
  const apiHostname = this.options.apiHostname || DEFAULT_HOSTNAME;
57
58
  const port = this.options.port;
@@ -65,6 +66,8 @@ class WorkOS {
65
66
  userAgent += ` ${name}: ${version}`;
66
67
  }
67
68
  this.webhooks = this.createWebhookClient();
69
+ // Must initialize UserManagement after baseURL is configured
70
+ this.userManagement = new user_management_1.UserManagement(this);
68
71
  this.client = this.createHttpClient(options, userAgent);
69
72
  }
70
73
  createWebhookClient() {
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "7.14.0",
2
+ "version": "7.15.0",
3
3
  "name": "@workos-inc/node",
4
4
  "author": "WorkOS",
5
5
  "description": "A Node wrapper for the WorkOS API",
@@ -37,6 +37,8 @@
37
37
  "prepublishOnly": "yarn run build"
38
38
  },
39
39
  "dependencies": {
40
+ "iron-session": "~6.3.1",
41
+ "jose": "~5.6.3",
40
42
  "pluralize": "8.0.0"
41
43
  },
42
44
  "devDependencies": {
@@ -63,4 +65,4 @@
63
65
  "default": "./lib/index.js"
64
66
  }
65
67
  }
66
- }
68
+ }