@mastra/auth-workos 1.0.0 → 1.1.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.
- package/CHANGELOG.md +76 -0
- package/LICENSE.md +15 -0
- package/dist/admin-portal.d.ts +77 -0
- package/dist/admin-portal.d.ts.map +1 -0
- package/dist/auth-provider.d.ts +137 -0
- package/dist/auth-provider.d.ts.map +1 -0
- package/dist/directory-sync.d.ts +129 -0
- package/dist/directory-sync.d.ts.map +1 -0
- package/dist/index.cjs +835 -130
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +42 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +832 -132
- package/dist/index.js.map +1 -1
- package/dist/rbac-provider.d.ts +129 -0
- package/dist/rbac-provider.d.ts.map +1 -0
- package/dist/session-storage.d.ts +25 -0
- package/dist/session-storage.d.ts.map +1 -0
- package/dist/types.d.ts +196 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +16 -10
package/dist/index.js
CHANGED
|
@@ -1,176 +1,876 @@
|
|
|
1
1
|
import { verifyJwks } from '@mastra/auth';
|
|
2
|
-
import {
|
|
2
|
+
import { MastraAuthProvider } from '@mastra/core/server';
|
|
3
|
+
import { CookieSessionStorage, AuthService, sessionEncryption } from '@workos/authkit-session';
|
|
4
|
+
import { WorkOS, GeneratePortalLinkIntent } from '@workos-inc/node';
|
|
5
|
+
import { resolvePermissionsFromMapping, matchesPermission } from '@mastra/core/auth/ee';
|
|
6
|
+
import { LRUCache } from 'lru-cache';
|
|
3
7
|
|
|
4
|
-
// src/
|
|
8
|
+
// src/auth-provider.ts
|
|
9
|
+
var WebSessionStorage = class extends CookieSessionStorage {
|
|
10
|
+
constructor(config) {
|
|
11
|
+
super(config);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Extract the encrypted session cookie from a Request.
|
|
15
|
+
*
|
|
16
|
+
* @param request - Standard Web Request object
|
|
17
|
+
* @returns The encrypted session string or null if not present
|
|
18
|
+
*/
|
|
19
|
+
async getSession(request) {
|
|
20
|
+
const cookieHeader = request.headers.get("Cookie");
|
|
21
|
+
if (!cookieHeader) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const cookies = cookieHeader.split(";").reduce(
|
|
25
|
+
(acc, cookie) => {
|
|
26
|
+
const [name, ...valueParts] = cookie.trim().split("=");
|
|
27
|
+
if (name) {
|
|
28
|
+
acc[name] = decodeURIComponent(valueParts.join("="));
|
|
29
|
+
}
|
|
30
|
+
return acc;
|
|
31
|
+
},
|
|
32
|
+
{}
|
|
33
|
+
);
|
|
34
|
+
return cookies[this.cookieName] || null;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
5
37
|
|
|
6
|
-
//
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
// src/types.ts
|
|
39
|
+
function mapWorkOSUserToEEUser(user) {
|
|
40
|
+
return {
|
|
41
|
+
id: user.id,
|
|
42
|
+
email: user.email,
|
|
43
|
+
name: user.firstName && user.lastName ? `${user.firstName} ${user.lastName}` : user.firstName || user.email,
|
|
44
|
+
avatarUrl: user.profilePictureUrl ?? void 0,
|
|
45
|
+
metadata: {
|
|
46
|
+
workosId: user.id,
|
|
47
|
+
emailVerified: user.emailVerified,
|
|
48
|
+
createdAt: user.createdAt
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/auth-provider.ts
|
|
54
|
+
var DEV_COOKIE_PASSWORD = crypto.randomUUID() + crypto.randomUUID();
|
|
55
|
+
var MastraAuthWorkos = class extends MastraAuthProvider {
|
|
56
|
+
workos;
|
|
57
|
+
clientId;
|
|
58
|
+
redirectUri;
|
|
59
|
+
ssoConfig;
|
|
60
|
+
authService;
|
|
61
|
+
config;
|
|
62
|
+
constructor(options) {
|
|
63
|
+
super({ name: options?.name ?? "workos" });
|
|
64
|
+
const apiKey = options?.apiKey ?? process.env.WORKOS_API_KEY;
|
|
65
|
+
const clientId = options?.clientId ?? process.env.WORKOS_CLIENT_ID;
|
|
66
|
+
const redirectUri = options?.redirectUri ?? process.env.WORKOS_REDIRECT_URI;
|
|
67
|
+
const cookiePassword = options?.session?.cookiePassword ?? process.env.WORKOS_COOKIE_PASSWORD ?? DEV_COOKIE_PASSWORD;
|
|
68
|
+
if (!apiKey || !clientId) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
"WorkOS API key and client ID are required. Provide them in the options or set WORKOS_API_KEY and WORKOS_CLIENT_ID environment variables."
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
if (!redirectUri) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
"WorkOS redirect URI is required. Provide it in the options or set WORKOS_REDIRECT_URI environment variable."
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
if (cookiePassword.length < 32) {
|
|
79
|
+
throw new Error(
|
|
80
|
+
"Cookie password must be at least 32 characters. Set WORKOS_COOKIE_PASSWORD environment variable or provide session.cookiePassword option."
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
this.clientId = clientId;
|
|
84
|
+
this.redirectUri = redirectUri;
|
|
85
|
+
this.ssoConfig = options?.sso;
|
|
86
|
+
this.workos = new WorkOS(apiKey, { clientId });
|
|
87
|
+
this.config = {
|
|
88
|
+
clientId,
|
|
89
|
+
apiKey,
|
|
90
|
+
redirectUri,
|
|
91
|
+
cookiePassword,
|
|
92
|
+
cookieName: options?.session?.cookieName ?? "wos_session",
|
|
93
|
+
cookieMaxAge: options?.session?.maxAge ?? 60 * 60 * 24 * 400,
|
|
94
|
+
// 400 days
|
|
95
|
+
cookieSameSite: options?.session?.sameSite?.toLowerCase(),
|
|
96
|
+
cookieDomain: void 0,
|
|
97
|
+
apiHttps: true
|
|
38
98
|
};
|
|
99
|
+
const storage = new WebSessionStorage(this.config);
|
|
100
|
+
this.authService = new AuthService(this.config, storage, this.workos, sessionEncryption);
|
|
101
|
+
this.registerOptions(options);
|
|
102
|
+
if (cookiePassword === DEV_COOKIE_PASSWORD) {
|
|
103
|
+
console.warn(
|
|
104
|
+
"[WorkOS] Using auto-generated cookie password for development. Sessions will not persist across server restarts. Set WORKOS_COOKIE_PASSWORD for persistent sessions."
|
|
105
|
+
);
|
|
106
|
+
}
|
|
39
107
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
108
|
+
// ============================================================================
|
|
109
|
+
// MastraAuthProvider Implementation
|
|
110
|
+
// ============================================================================
|
|
111
|
+
/**
|
|
112
|
+
* Authenticate a bearer token or session cookie.
|
|
113
|
+
*
|
|
114
|
+
* Uses AuthKit's withAuth() for cookie-based sessions, falls back to
|
|
115
|
+
* JWT verification for bearer tokens.
|
|
116
|
+
*/
|
|
117
|
+
async authenticateToken(token, request) {
|
|
118
|
+
try {
|
|
119
|
+
const rawRequest = "raw" in request ? request.raw : request;
|
|
120
|
+
const { auth } = await this.authService.withAuth(rawRequest);
|
|
121
|
+
if (auth.user) {
|
|
122
|
+
return {
|
|
123
|
+
...mapWorkOSUserToEEUser(auth.user),
|
|
124
|
+
workosId: auth.user.id,
|
|
125
|
+
organizationId: auth.organizationId
|
|
126
|
+
// Note: memberships not available from session, fetch if needed
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
if (token) {
|
|
130
|
+
const jwksUri = this.workos.userManagement.getJwksUrl(this.clientId);
|
|
131
|
+
const payload = await verifyJwks(token, jwksUri);
|
|
132
|
+
if (payload?.sub) {
|
|
133
|
+
const user = await this.workos.userManagement.getUser(payload.sub);
|
|
134
|
+
const memberships = await this.workos.userManagement.listOrganizationMemberships({
|
|
135
|
+
userId: user.id
|
|
136
|
+
});
|
|
137
|
+
return {
|
|
138
|
+
...mapWorkOSUserToEEUser(user),
|
|
139
|
+
workosId: user.id,
|
|
140
|
+
organizationId: memberships.data[0]?.organizationId,
|
|
141
|
+
memberships: memberships.data
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return null;
|
|
146
|
+
} catch {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
60
149
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
150
|
+
/**
|
|
151
|
+
* Authorize a user for access.
|
|
152
|
+
*/
|
|
153
|
+
async authorizeUser(user) {
|
|
154
|
+
return !!user?.id && !!user?.workosId;
|
|
65
155
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
156
|
+
// ============================================================================
|
|
157
|
+
// IUserProvider Implementation
|
|
158
|
+
// ============================================================================
|
|
159
|
+
/**
|
|
160
|
+
* Get the current user from the request using AuthKit session.
|
|
161
|
+
*/
|
|
162
|
+
async getCurrentUser(request) {
|
|
163
|
+
try {
|
|
164
|
+
const { auth, refreshedSessionData } = await this.authService.withAuth(request);
|
|
165
|
+
if (!auth.user) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
let organizationId = auth.organizationId;
|
|
169
|
+
if (!organizationId) {
|
|
170
|
+
try {
|
|
171
|
+
const memberships = await this.workos.userManagement.listOrganizationMemberships({
|
|
172
|
+
userId: auth.user.id
|
|
173
|
+
});
|
|
174
|
+
organizationId = memberships.data[0]?.organizationId;
|
|
175
|
+
} catch {
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
const user = {
|
|
179
|
+
...mapWorkOSUserToEEUser(auth.user),
|
|
180
|
+
workosId: auth.user.id,
|
|
181
|
+
organizationId
|
|
182
|
+
};
|
|
183
|
+
if (refreshedSessionData) {
|
|
184
|
+
user._refreshedSessionData = refreshedSessionData;
|
|
185
|
+
}
|
|
186
|
+
return user;
|
|
187
|
+
} catch {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Get a user by their ID.
|
|
193
|
+
*/
|
|
194
|
+
async getUser(userId) {
|
|
195
|
+
try {
|
|
196
|
+
const user = await this.workos.userManagement.getUser(userId);
|
|
197
|
+
return {
|
|
198
|
+
...mapWorkOSUserToEEUser(user),
|
|
199
|
+
workosId: user.id
|
|
200
|
+
};
|
|
201
|
+
} catch {
|
|
202
|
+
return null;
|
|
69
203
|
}
|
|
70
204
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
205
|
+
/**
|
|
206
|
+
* Get the URL to the user's profile page.
|
|
207
|
+
*/
|
|
208
|
+
getUserProfileUrl(user) {
|
|
209
|
+
return `/profile/${user.id}`;
|
|
210
|
+
}
|
|
211
|
+
// ============================================================================
|
|
212
|
+
// ISSOProvider Implementation
|
|
213
|
+
// ============================================================================
|
|
214
|
+
/**
|
|
215
|
+
* Get the URL to redirect users to for SSO login.
|
|
216
|
+
*/
|
|
217
|
+
getLoginUrl(redirectUri, state) {
|
|
218
|
+
const baseOptions = {
|
|
219
|
+
clientId: this.clientId,
|
|
220
|
+
redirectUri: redirectUri || this.redirectUri,
|
|
221
|
+
state
|
|
222
|
+
};
|
|
223
|
+
if (this.ssoConfig?.connection) {
|
|
224
|
+
return this.workos.userManagement.getAuthorizationUrl({
|
|
225
|
+
...baseOptions,
|
|
226
|
+
connectionId: this.ssoConfig.connection
|
|
227
|
+
});
|
|
228
|
+
} else if (this.ssoConfig?.provider) {
|
|
229
|
+
return this.workos.userManagement.getAuthorizationUrl({
|
|
230
|
+
...baseOptions,
|
|
231
|
+
provider: this.ssoConfig.provider
|
|
232
|
+
});
|
|
233
|
+
} else if (this.ssoConfig?.defaultOrganization) {
|
|
234
|
+
return this.workos.userManagement.getAuthorizationUrl({
|
|
235
|
+
...baseOptions,
|
|
236
|
+
organizationId: this.ssoConfig.defaultOrganization
|
|
237
|
+
});
|
|
74
238
|
}
|
|
239
|
+
return this.workos.userManagement.getAuthorizationUrl({
|
|
240
|
+
...baseOptions,
|
|
241
|
+
provider: "authkit"
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Handle the OAuth callback from WorkOS.
|
|
246
|
+
*
|
|
247
|
+
* Uses AuthKit's handleCallback for proper session creation.
|
|
248
|
+
*/
|
|
249
|
+
async handleCallback(code, _state) {
|
|
250
|
+
const result = await this.authService.handleCallback(
|
|
251
|
+
new Request("http://localhost"),
|
|
252
|
+
// Dummy request, not used
|
|
253
|
+
new Response(),
|
|
254
|
+
// Dummy response to get headers
|
|
255
|
+
{ code, state: _state }
|
|
256
|
+
);
|
|
257
|
+
const user = {
|
|
258
|
+
...mapWorkOSUserToEEUser(result.authResponse.user),
|
|
259
|
+
workosId: result.authResponse.user.id,
|
|
260
|
+
organizationId: result.authResponse.organizationId
|
|
261
|
+
};
|
|
262
|
+
const sessionCookie = result.headers?.["Set-Cookie"];
|
|
263
|
+
const cookies = sessionCookie ? Array.isArray(sessionCookie) ? sessionCookie : [sessionCookie] : void 0;
|
|
264
|
+
return {
|
|
265
|
+
user,
|
|
266
|
+
tokens: {
|
|
267
|
+
accessToken: result.authResponse.accessToken,
|
|
268
|
+
refreshToken: result.authResponse.refreshToken
|
|
269
|
+
},
|
|
270
|
+
cookies
|
|
271
|
+
};
|
|
75
272
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
273
|
+
/**
|
|
274
|
+
* Get the URL to redirect users to for logout.
|
|
275
|
+
* Extracts session ID from the request's JWT to build a valid WorkOS logout URL.
|
|
276
|
+
*
|
|
277
|
+
* @param redirectUri - URL to redirect to after logout
|
|
278
|
+
* @param request - Request containing session cookie (needed to extract sid)
|
|
279
|
+
* @returns Logout URL or null if no active session
|
|
280
|
+
*/
|
|
281
|
+
async getLogoutUrl(redirectUri, request) {
|
|
282
|
+
if (!request) {
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
try {
|
|
286
|
+
const { auth } = await this.authService.withAuth(request);
|
|
287
|
+
if (!auth.user) {
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
const [, payloadBase64] = auth.accessToken.split(".");
|
|
291
|
+
if (!payloadBase64) {
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
const payload = JSON.parse(atob(payloadBase64));
|
|
295
|
+
const sessionId = payload.sid;
|
|
296
|
+
if (!sessionId) {
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
return this.workos.userManagement.getLogoutUrl({ sessionId, returnTo: redirectUri });
|
|
300
|
+
} catch {
|
|
301
|
+
return null;
|
|
79
302
|
}
|
|
80
303
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
304
|
+
/**
|
|
305
|
+
* Get the configuration for rendering the login button.
|
|
306
|
+
*/
|
|
307
|
+
getLoginButtonConfig() {
|
|
308
|
+
let text = "Sign in";
|
|
309
|
+
if (this.ssoConfig?.provider) {
|
|
310
|
+
const providerNames = {
|
|
311
|
+
GoogleOAuth: "Google",
|
|
312
|
+
MicrosoftOAuth: "Microsoft",
|
|
313
|
+
GitHubOAuth: "GitHub",
|
|
314
|
+
AppleOAuth: "Apple"
|
|
315
|
+
};
|
|
316
|
+
const providerName = providerNames[this.ssoConfig.provider];
|
|
317
|
+
if (providerName) {
|
|
318
|
+
text = `Sign in with ${providerName}`;
|
|
319
|
+
}
|
|
84
320
|
}
|
|
321
|
+
return {
|
|
322
|
+
provider: "workos",
|
|
323
|
+
text
|
|
324
|
+
};
|
|
85
325
|
}
|
|
86
|
-
|
|
87
|
-
|
|
326
|
+
// ============================================================================
|
|
327
|
+
// ISessionProvider Implementation
|
|
328
|
+
// ============================================================================
|
|
329
|
+
/**
|
|
330
|
+
* Create a new session for a user.
|
|
331
|
+
*
|
|
332
|
+
* Note: With AuthKit, sessions are created via handleCallback.
|
|
333
|
+
* This method is kept for interface compatibility.
|
|
334
|
+
*/
|
|
335
|
+
async createSession(userId, metadata) {
|
|
336
|
+
const sessionId = crypto.randomUUID();
|
|
337
|
+
const now = /* @__PURE__ */ new Date();
|
|
338
|
+
const expiresAt = new Date(now.getTime() + this.config.cookieMaxAge * 1e3);
|
|
339
|
+
return {
|
|
340
|
+
id: sessionId,
|
|
341
|
+
userId,
|
|
342
|
+
createdAt: now,
|
|
343
|
+
expiresAt,
|
|
344
|
+
metadata
|
|
345
|
+
};
|
|
88
346
|
}
|
|
89
|
-
|
|
90
|
-
|
|
347
|
+
/**
|
|
348
|
+
* Validate a session.
|
|
349
|
+
*
|
|
350
|
+
* With AuthKit, sessions are validated via withAuth().
|
|
351
|
+
*/
|
|
352
|
+
async validateSession(_sessionId) {
|
|
353
|
+
return null;
|
|
91
354
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
355
|
+
/**
|
|
356
|
+
* Destroy a session.
|
|
357
|
+
*/
|
|
358
|
+
async destroySession(_sessionId) {
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Refresh a session.
|
|
362
|
+
*/
|
|
363
|
+
async refreshSession(_sessionId) {
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Extract session ID from a request.
|
|
368
|
+
*/
|
|
369
|
+
getSessionIdFromRequest(_request) {
|
|
370
|
+
return null;
|
|
103
371
|
}
|
|
104
372
|
/**
|
|
105
|
-
*
|
|
106
|
-
* @param logger
|
|
373
|
+
* Get response headers to set the session cookie.
|
|
107
374
|
*/
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if (
|
|
111
|
-
|
|
375
|
+
getSessionHeaders(session) {
|
|
376
|
+
const sessionCookie = session._sessionCookie;
|
|
377
|
+
if (sessionCookie) {
|
|
378
|
+
return { "Set-Cookie": Array.isArray(sessionCookie) ? sessionCookie[0] : sessionCookie };
|
|
112
379
|
}
|
|
380
|
+
return {};
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Get response headers to clear the session cookie.
|
|
384
|
+
*/
|
|
385
|
+
getClearSessionHeaders() {
|
|
386
|
+
const cookieParts = [`${this.config.cookieName}=`, "Path=/", "Max-Age=0", "HttpOnly"];
|
|
387
|
+
return { "Set-Cookie": cookieParts.join("; ") };
|
|
388
|
+
}
|
|
389
|
+
// ============================================================================
|
|
390
|
+
// Helper Methods
|
|
391
|
+
// ============================================================================
|
|
392
|
+
/**
|
|
393
|
+
* Get the underlying WorkOS client.
|
|
394
|
+
*/
|
|
395
|
+
getWorkOS() {
|
|
396
|
+
return this.workos;
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Get the AuthKit AuthService.
|
|
400
|
+
*/
|
|
401
|
+
getAuthService() {
|
|
402
|
+
return this.authService;
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Get the configured client ID.
|
|
406
|
+
*/
|
|
407
|
+
getClientId() {
|
|
408
|
+
return this.clientId;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Get the configured redirect URI.
|
|
412
|
+
*/
|
|
413
|
+
getRedirectUri() {
|
|
414
|
+
return this.redirectUri;
|
|
113
415
|
}
|
|
114
416
|
};
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
var
|
|
118
|
-
|
|
119
|
-
|
|
417
|
+
var DEFAULT_CACHE_TTL_MS = 60 * 1e3;
|
|
418
|
+
var DEFAULT_CACHE_MAX_SIZE = 1e3;
|
|
419
|
+
var MastraRBACWorkos = class {
|
|
420
|
+
workos;
|
|
421
|
+
options;
|
|
422
|
+
/**
|
|
423
|
+
* Single cache for roles (the expensive WorkOS API call).
|
|
424
|
+
* Permissions are derived from roles on-the-fly (cheap, synchronous).
|
|
425
|
+
* Storing promises handles concurrent request deduplication.
|
|
426
|
+
*/
|
|
427
|
+
rolesCache;
|
|
428
|
+
/**
|
|
429
|
+
* Expose roleMapping for middleware access.
|
|
430
|
+
* This allows the authorization middleware to resolve permissions
|
|
431
|
+
* without needing to call the async methods.
|
|
432
|
+
*/
|
|
433
|
+
get roleMapping() {
|
|
434
|
+
return this.options.roleMapping;
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Create a new WorkOS RBAC provider.
|
|
438
|
+
*
|
|
439
|
+
* @param options - RBAC configuration options
|
|
440
|
+
*/
|
|
120
441
|
constructor(options) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
442
|
+
const apiKey = options.apiKey ?? process.env.WORKOS_API_KEY;
|
|
443
|
+
const clientId = options.clientId ?? process.env.WORKOS_CLIENT_ID;
|
|
444
|
+
if (!apiKey || !clientId) {
|
|
445
|
+
throw new Error(
|
|
446
|
+
"WorkOS API key and client ID are required. Provide them in the options or set WORKOS_API_KEY and WORKOS_CLIENT_ID environment variables."
|
|
447
|
+
);
|
|
124
448
|
}
|
|
125
|
-
this.
|
|
126
|
-
this.
|
|
449
|
+
this.workos = new WorkOS(apiKey, { clientId });
|
|
450
|
+
this.options = options;
|
|
451
|
+
this.rolesCache = new LRUCache({
|
|
452
|
+
max: options.cache?.maxSize ?? DEFAULT_CACHE_MAX_SIZE,
|
|
453
|
+
ttl: options.cache?.ttlMs ?? DEFAULT_CACHE_TTL_MS
|
|
454
|
+
});
|
|
127
455
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
456
|
+
/**
|
|
457
|
+
* Get all roles for a user from their WorkOS organization memberships.
|
|
458
|
+
*
|
|
459
|
+
* Fetches organization memberships from WorkOS and extracts role slugs.
|
|
460
|
+
* If an organizationId is configured, only returns roles from that organization.
|
|
461
|
+
* Otherwise, returns roles from all organizations the user belongs to.
|
|
462
|
+
*
|
|
463
|
+
* Results are cached and concurrent requests are deduplicated.
|
|
464
|
+
*
|
|
465
|
+
* @param user - WorkOS user to get roles for
|
|
466
|
+
* @returns Array of role slugs
|
|
467
|
+
*/
|
|
468
|
+
async getRoles(user) {
|
|
469
|
+
if (user.memberships && user.memberships.length > 0) {
|
|
470
|
+
return this.extractRolesFromMemberships(user);
|
|
131
471
|
}
|
|
132
|
-
|
|
133
|
-
|
|
472
|
+
const cacheKey = user.workosId ?? user.id;
|
|
473
|
+
const cached = this.rolesCache.get(cacheKey);
|
|
474
|
+
if (cached) {
|
|
475
|
+
return cached;
|
|
476
|
+
}
|
|
477
|
+
const rolesPromise = this.fetchRolesFromWorkOS(user);
|
|
478
|
+
this.rolesCache.set(cacheKey, rolesPromise);
|
|
479
|
+
return rolesPromise;
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Fetch roles from WorkOS API.
|
|
483
|
+
*/
|
|
484
|
+
async fetchRolesFromWorkOS(user) {
|
|
485
|
+
try {
|
|
486
|
+
const memberships = await this.workos.userManagement.listOrganizationMemberships({
|
|
487
|
+
userId: user.workosId
|
|
488
|
+
});
|
|
489
|
+
const relevantMemberships = this.options.organizationId ? memberships.data.filter((m) => m.organizationId === this.options.organizationId) : memberships.data;
|
|
490
|
+
return relevantMemberships.map((m) => m.role.slug);
|
|
491
|
+
} catch {
|
|
492
|
+
return [];
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Check if a user has a specific role.
|
|
497
|
+
*
|
|
498
|
+
* @param user - WorkOS user to check
|
|
499
|
+
* @param role - Role slug to check for
|
|
500
|
+
* @returns True if user has the role
|
|
501
|
+
*/
|
|
502
|
+
async hasRole(user, role) {
|
|
503
|
+
const roles = await this.getRoles(user);
|
|
504
|
+
return roles.includes(role);
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Get all permissions for a user by mapping their WorkOS roles.
|
|
508
|
+
*
|
|
509
|
+
* Uses the configured roleMapping to translate WorkOS role slugs
|
|
510
|
+
* into Mastra permission strings. Roles are cached; permissions
|
|
511
|
+
* are derived on-the-fly (cheap, synchronous operation).
|
|
512
|
+
*
|
|
513
|
+
* If the user has no roles (no organization memberships), the
|
|
514
|
+
* _default permissions from the role mapping are applied.
|
|
515
|
+
*
|
|
516
|
+
* @param user - WorkOS user to get permissions for
|
|
517
|
+
* @returns Array of permission strings
|
|
518
|
+
*/
|
|
519
|
+
async getPermissions(user) {
|
|
520
|
+
const roles = await this.getRoles(user);
|
|
521
|
+
if (roles.length === 0) {
|
|
522
|
+
return this.options.roleMapping["_default"] ?? [];
|
|
134
523
|
}
|
|
135
|
-
|
|
136
|
-
|
|
524
|
+
return resolvePermissionsFromMapping(roles, this.options.roleMapping);
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Check if a user has a specific permission.
|
|
528
|
+
*
|
|
529
|
+
* Uses wildcard matching to check if any of the user's permissions
|
|
530
|
+
* grant access to the required permission.
|
|
531
|
+
*
|
|
532
|
+
* @param user - WorkOS user to check
|
|
533
|
+
* @param permission - Permission to check for (e.g., 'agents:read')
|
|
534
|
+
* @returns True if user has the permission
|
|
535
|
+
*/
|
|
536
|
+
async hasPermission(user, permission) {
|
|
537
|
+
const permissions = await this.getPermissions(user);
|
|
538
|
+
return permissions.some((p) => matchesPermission(p, permission));
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Check if a user has ALL of the specified permissions.
|
|
542
|
+
*
|
|
543
|
+
* @param user - WorkOS user to check
|
|
544
|
+
* @param permissions - Array of permissions to check for
|
|
545
|
+
* @returns True if user has all permissions
|
|
546
|
+
*/
|
|
547
|
+
async hasAllPermissions(user, permissions) {
|
|
548
|
+
const userPermissions = await this.getPermissions(user);
|
|
549
|
+
return permissions.every((required) => userPermissions.some((p) => matchesPermission(p, required)));
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Check if a user has ANY of the specified permissions.
|
|
553
|
+
*
|
|
554
|
+
* @param user - WorkOS user to check
|
|
555
|
+
* @param permissions - Array of permissions to check for
|
|
556
|
+
* @returns True if user has at least one permission
|
|
557
|
+
*/
|
|
558
|
+
async hasAnyPermission(user, permissions) {
|
|
559
|
+
const userPermissions = await this.getPermissions(user);
|
|
560
|
+
return permissions.some((required) => userPermissions.some((p) => matchesPermission(p, required)));
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Clear the roles cache.
|
|
564
|
+
*
|
|
565
|
+
* Call this when system-wide role changes occur.
|
|
566
|
+
* For individual user changes, prefer clearUserCache() instead.
|
|
567
|
+
*/
|
|
568
|
+
clearCache() {
|
|
569
|
+
this.rolesCache.clear();
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Clear cached roles for a specific user.
|
|
573
|
+
*
|
|
574
|
+
* Call this when a user's roles change to ensure fresh permission resolution
|
|
575
|
+
* on their next request. This is more efficient than clearing the entire cache.
|
|
576
|
+
*
|
|
577
|
+
* @param userId - The user ID to clear from cache
|
|
578
|
+
*/
|
|
579
|
+
clearUserCache(userId) {
|
|
580
|
+
this.rolesCache.delete(userId);
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Get cache statistics for monitoring.
|
|
584
|
+
*
|
|
585
|
+
* @returns Object with cache size and max size
|
|
586
|
+
*/
|
|
587
|
+
getCacheStats() {
|
|
588
|
+
return {
|
|
589
|
+
size: this.rolesCache.size,
|
|
590
|
+
maxSize: this.rolesCache.max
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Extract role slugs from memberships attached to the user object.
|
|
595
|
+
*
|
|
596
|
+
* @param user - WorkOS user with memberships
|
|
597
|
+
* @returns Array of role slugs
|
|
598
|
+
*/
|
|
599
|
+
extractRolesFromMemberships(user) {
|
|
600
|
+
if (!user.memberships) {
|
|
601
|
+
return [];
|
|
137
602
|
}
|
|
603
|
+
const relevantMemberships = this.options.organizationId ? user.memberships.filter((m) => m.organizationId === this.options.organizationId) : user.memberships;
|
|
604
|
+
return relevantMemberships.map((m) => m.role.slug);
|
|
138
605
|
}
|
|
139
606
|
};
|
|
140
|
-
|
|
607
|
+
|
|
608
|
+
// src/directory-sync.ts
|
|
609
|
+
var WorkOSDirectorySync = class {
|
|
141
610
|
workos;
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
611
|
+
webhookSecret;
|
|
612
|
+
handlers;
|
|
613
|
+
/**
|
|
614
|
+
* Creates a new WorkOSDirectorySync instance.
|
|
615
|
+
*
|
|
616
|
+
* @param workos - WorkOS client instance
|
|
617
|
+
* @param options - Configuration options including webhook secret and event handlers
|
|
618
|
+
* @throws Error if webhook secret is not provided
|
|
619
|
+
*/
|
|
620
|
+
constructor(workos, options) {
|
|
621
|
+
this.workos = workos;
|
|
622
|
+
const webhookSecret = options.webhookSecret ?? process.env.WORKOS_WEBHOOK_SECRET;
|
|
623
|
+
if (!webhookSecret) {
|
|
147
624
|
throw new Error(
|
|
148
|
-
"WorkOS
|
|
625
|
+
"WorkOS webhook secret is required. Provide it in options or set WORKOS_WEBHOOK_SECRET environment variable."
|
|
149
626
|
);
|
|
150
627
|
}
|
|
151
|
-
this.
|
|
152
|
-
|
|
153
|
-
});
|
|
154
|
-
this.registerOptions(options);
|
|
628
|
+
this.webhookSecret = webhookSecret;
|
|
629
|
+
this.handlers = options.handlers;
|
|
155
630
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
631
|
+
/**
|
|
632
|
+
* Handles incoming webhook events from WorkOS Directory Sync.
|
|
633
|
+
*
|
|
634
|
+
* This method verifies the webhook signature for security, parses the event,
|
|
635
|
+
* and routes it to the appropriate handler based on the event type.
|
|
636
|
+
*
|
|
637
|
+
* @param payload - Raw webhook payload (string or object)
|
|
638
|
+
* @param signature - WorkOS signature header for verification
|
|
639
|
+
* @throws Error if signature verification fails
|
|
640
|
+
*/
|
|
641
|
+
async handleWebhook(payload, signature) {
|
|
642
|
+
const parsedPayload = typeof payload === "string" ? JSON.parse(payload) : payload;
|
|
643
|
+
const event = await this.workos.webhooks.constructEvent({
|
|
644
|
+
payload: parsedPayload,
|
|
645
|
+
sigHeader: signature,
|
|
646
|
+
secret: this.webhookSecret
|
|
647
|
+
});
|
|
648
|
+
try {
|
|
649
|
+
await this.routeEvent(event);
|
|
650
|
+
} catch (error) {
|
|
651
|
+
console.error(`[WorkOSDirectorySync] Error handling event ${event.event}:`, error);
|
|
652
|
+
}
|
|
160
653
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
654
|
+
/**
|
|
655
|
+
* Routes a directory sync event to the appropriate handler.
|
|
656
|
+
*
|
|
657
|
+
* @param event - The verified webhook event
|
|
658
|
+
*/
|
|
659
|
+
async routeEvent(event) {
|
|
660
|
+
const { event: eventType, data } = event;
|
|
661
|
+
switch (eventType) {
|
|
662
|
+
case "dsync.user.created":
|
|
663
|
+
if (this.handlers.onUserCreated) {
|
|
664
|
+
await this.handlers.onUserCreated(this.mapUserData(data));
|
|
665
|
+
}
|
|
666
|
+
break;
|
|
667
|
+
case "dsync.user.updated":
|
|
668
|
+
if (this.handlers.onUserUpdated) {
|
|
669
|
+
await this.handlers.onUserUpdated(this.mapUserData(data));
|
|
670
|
+
}
|
|
671
|
+
break;
|
|
672
|
+
case "dsync.user.deleted":
|
|
673
|
+
if (this.handlers.onUserDeleted) {
|
|
674
|
+
await this.handlers.onUserDeleted(this.mapUserData(data));
|
|
675
|
+
}
|
|
676
|
+
break;
|
|
677
|
+
case "dsync.group.created":
|
|
678
|
+
if (this.handlers.onGroupCreated) {
|
|
679
|
+
await this.handlers.onGroupCreated(this.mapGroupData(data));
|
|
680
|
+
}
|
|
681
|
+
break;
|
|
682
|
+
case "dsync.group.updated":
|
|
683
|
+
if (this.handlers.onGroupUpdated) {
|
|
684
|
+
await this.handlers.onGroupUpdated(this.mapGroupData(data));
|
|
685
|
+
}
|
|
686
|
+
break;
|
|
687
|
+
case "dsync.group.deleted":
|
|
688
|
+
if (this.handlers.onGroupDeleted) {
|
|
689
|
+
await this.handlers.onGroupDeleted(this.mapGroupData(data));
|
|
690
|
+
}
|
|
691
|
+
break;
|
|
692
|
+
case "dsync.group.user_added":
|
|
693
|
+
if (this.handlers.onGroupUserAdded) {
|
|
694
|
+
await this.handlers.onGroupUserAdded({
|
|
695
|
+
group: this.mapGroupData(data.group),
|
|
696
|
+
user: this.mapUserData(data.user)
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
break;
|
|
700
|
+
case "dsync.group.user_removed":
|
|
701
|
+
if (this.handlers.onGroupUserRemoved) {
|
|
702
|
+
await this.handlers.onGroupUserRemoved({
|
|
703
|
+
group: this.mapGroupData(data.group),
|
|
704
|
+
user: this.mapUserData(data.user)
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
break;
|
|
708
|
+
default:
|
|
709
|
+
console.warn(`[WorkOSDirectorySync] Unknown event type: ${eventType}`);
|
|
164
710
|
}
|
|
165
|
-
|
|
166
|
-
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* Maps raw webhook user data to the DirectorySyncUserData type.
|
|
714
|
+
*
|
|
715
|
+
* @param data - Raw user data from webhook
|
|
716
|
+
* @returns Typed user data
|
|
717
|
+
*/
|
|
718
|
+
mapUserData(data) {
|
|
719
|
+
return {
|
|
720
|
+
id: data.id,
|
|
721
|
+
directoryId: data.directory_id,
|
|
722
|
+
organizationId: data.organization_id,
|
|
723
|
+
idpId: data.idp_id,
|
|
724
|
+
firstName: data.first_name,
|
|
725
|
+
lastName: data.last_name,
|
|
726
|
+
jobTitle: data.job_title,
|
|
727
|
+
emails: data.emails ?? [],
|
|
728
|
+
username: data.username,
|
|
729
|
+
groups: data.groups ?? [],
|
|
730
|
+
state: data.state,
|
|
731
|
+
rawAttributes: data.raw_attributes ?? {},
|
|
732
|
+
customAttributes: data.custom_attributes ?? {},
|
|
733
|
+
createdAt: data.created_at,
|
|
734
|
+
updatedAt: data.updated_at
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* Maps raw webhook group data to the DirectorySyncGroupData type.
|
|
739
|
+
*
|
|
740
|
+
* @param data - Raw group data from webhook
|
|
741
|
+
* @returns Typed group data
|
|
742
|
+
*/
|
|
743
|
+
mapGroupData(data) {
|
|
744
|
+
return {
|
|
745
|
+
id: data.id,
|
|
746
|
+
directoryId: data.directory_id,
|
|
747
|
+
organizationId: data.organization_id,
|
|
748
|
+
idpId: data.idp_id,
|
|
749
|
+
name: data.name,
|
|
750
|
+
createdAt: data.created_at,
|
|
751
|
+
updatedAt: data.updated_at,
|
|
752
|
+
rawAttributes: data.raw_attributes ?? {}
|
|
753
|
+
};
|
|
754
|
+
}
|
|
755
|
+
// ===========================================================================
|
|
756
|
+
// Helper Methods for Directory Sync Operations
|
|
757
|
+
// ===========================================================================
|
|
758
|
+
/**
|
|
759
|
+
* Lists all directories for an organization.
|
|
760
|
+
*
|
|
761
|
+
* @param organizationId - The WorkOS organization ID
|
|
762
|
+
* @returns Array of directories
|
|
763
|
+
*
|
|
764
|
+
* @example
|
|
765
|
+
* ```typescript
|
|
766
|
+
* const directories = await directorySync.listDirectories('org_123');
|
|
767
|
+
* for (const dir of directories) {
|
|
768
|
+
* console.log(`Directory: ${dir.name} (${dir.type})`);
|
|
769
|
+
* }
|
|
770
|
+
* ```
|
|
771
|
+
*/
|
|
772
|
+
async listDirectories(organizationId) {
|
|
773
|
+
const response = await this.workos.directorySync.listDirectories({
|
|
774
|
+
organizationId
|
|
775
|
+
});
|
|
776
|
+
return response.data;
|
|
777
|
+
}
|
|
778
|
+
/**
|
|
779
|
+
* Lists all users in a directory.
|
|
780
|
+
*
|
|
781
|
+
* @param directoryId - The directory ID
|
|
782
|
+
* @returns Array of directory users
|
|
783
|
+
*
|
|
784
|
+
* @example
|
|
785
|
+
* ```typescript
|
|
786
|
+
* const users = await directorySync.listDirectoryUsers('directory_123');
|
|
787
|
+
* for (const user of users) {
|
|
788
|
+
* console.log(`User: ${user.firstName} ${user.lastName}`);
|
|
789
|
+
* }
|
|
790
|
+
* ```
|
|
791
|
+
*/
|
|
792
|
+
async listDirectoryUsers(directoryId) {
|
|
793
|
+
const response = await this.workos.directorySync.listUsers({
|
|
794
|
+
directory: directoryId
|
|
795
|
+
});
|
|
796
|
+
return response.data;
|
|
797
|
+
}
|
|
798
|
+
/**
|
|
799
|
+
* Lists all groups in a directory.
|
|
800
|
+
*
|
|
801
|
+
* @param directoryId - The directory ID
|
|
802
|
+
* @returns Array of directory groups
|
|
803
|
+
*
|
|
804
|
+
* @example
|
|
805
|
+
* ```typescript
|
|
806
|
+
* const groups = await directorySync.listDirectoryGroups('directory_123');
|
|
807
|
+
* for (const group of groups) {
|
|
808
|
+
* console.log(`Group: ${group.name}`);
|
|
809
|
+
* }
|
|
810
|
+
* ```
|
|
811
|
+
*/
|
|
812
|
+
async listDirectoryGroups(directoryId) {
|
|
813
|
+
const response = await this.workos.directorySync.listGroups({
|
|
814
|
+
directory: directoryId
|
|
815
|
+
});
|
|
816
|
+
return response.data;
|
|
817
|
+
}
|
|
818
|
+
};
|
|
819
|
+
var INTENT_MAP = {
|
|
820
|
+
sso: GeneratePortalLinkIntent.SSO,
|
|
821
|
+
dsync: GeneratePortalLinkIntent.DSync,
|
|
822
|
+
audit_logs: GeneratePortalLinkIntent.AuditLogs,
|
|
823
|
+
log_streams: GeneratePortalLinkIntent.LogStreams
|
|
824
|
+
};
|
|
825
|
+
var WorkOSAdminPortal = class {
|
|
826
|
+
workos;
|
|
827
|
+
returnUrl;
|
|
828
|
+
/**
|
|
829
|
+
* Creates a new WorkOSAdminPortal instance.
|
|
830
|
+
*
|
|
831
|
+
* @param workos - The WorkOS client instance
|
|
832
|
+
* @param options - Configuration options for the Admin Portal
|
|
833
|
+
*/
|
|
834
|
+
constructor(workos, options) {
|
|
835
|
+
this.workos = workos;
|
|
836
|
+
this.returnUrl = options?.returnUrl ?? "/";
|
|
837
|
+
}
|
|
838
|
+
/**
|
|
839
|
+
* Generates a link to the WorkOS Admin Portal for a specific organization.
|
|
840
|
+
*
|
|
841
|
+
* The generated link is a one-time use URL that expires after a short period.
|
|
842
|
+
* Users should be redirected to this link immediately after generation.
|
|
843
|
+
*
|
|
844
|
+
* @param organizationId - The WorkOS organization ID (e.g., 'org_01H...')
|
|
845
|
+
* @param intent - The portal section to open. Determines what the user can configure:
|
|
846
|
+
* - `'sso'`: Configure SSO connections (SAML, OIDC providers)
|
|
847
|
+
* - `'dsync'`: Configure Directory Sync (SCIM provisioning)
|
|
848
|
+
* - `'audit_logs'`: View and export audit logs
|
|
849
|
+
* - `'log_streams'`: Configure log streaming to external SIEM systems
|
|
850
|
+
* @returns A promise that resolves to the Admin Portal URL
|
|
851
|
+
*
|
|
852
|
+
* @example
|
|
853
|
+
* ```typescript
|
|
854
|
+
* // SSO configuration (default)
|
|
855
|
+
* const link = await adminPortal.getPortalLink('org_01H...');
|
|
856
|
+
*
|
|
857
|
+
* // Directory Sync configuration
|
|
858
|
+
* const link = await adminPortal.getPortalLink('org_01H...', 'dsync');
|
|
859
|
+
*
|
|
860
|
+
* // Audit logs viewing
|
|
861
|
+
* const link = await adminPortal.getPortalLink('org_01H...', 'audit_logs');
|
|
862
|
+
* ```
|
|
863
|
+
*/
|
|
864
|
+
async getPortalLink(organizationId, intent) {
|
|
865
|
+
const result = await this.workos.portal.generateLink({
|
|
866
|
+
organization: organizationId,
|
|
867
|
+
intent: INTENT_MAP[intent ?? "sso"],
|
|
868
|
+
returnUrl: this.returnUrl
|
|
167
869
|
});
|
|
168
|
-
|
|
169
|
-
const isAdmin = roles.some((role) => role.slug === "admin");
|
|
170
|
-
return isAdmin;
|
|
870
|
+
return result.link;
|
|
171
871
|
}
|
|
172
872
|
};
|
|
173
873
|
|
|
174
|
-
export { MastraAuthWorkos };
|
|
874
|
+
export { MastraAuthWorkos, MastraRBACWorkos, WebSessionStorage, WorkOSAdminPortal, WorkOSDirectorySync, mapWorkOSUserToEEUser };
|
|
175
875
|
//# sourceMappingURL=index.js.map
|
|
176
876
|
//# sourceMappingURL=index.js.map
|