@mastra/auth-studio 0.0.0-auth-combined-test-all-20260302225441

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 ADDED
@@ -0,0 +1,8 @@
1
+ # @mastra/auth-studio
2
+
3
+ ## 0.0.0-auth-combined-test-all-20260302225441
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [[`88de7e8`](https://github.com/mastra-ai/mastra/commit/88de7e8dfe4b7e1951a9e441bb33136e705ce24e), [`cdc3c3a`](https://github.com/mastra-ai/mastra/commit/cdc3c3a1c0eb8462957720d9f9d6de953cb7897c), [`edee4b3`](https://github.com/mastra-ai/mastra/commit/edee4b37dff0af515fc7cc0e8d71ee39e6a762f0), [`d5f0d8d`](https://github.com/mastra-ai/mastra/commit/d5f0d8d6a03e515ddaa9b5da19b7e44b8357b07b), [`09c3b18`](https://github.com/mastra-ai/mastra/commit/09c3b1802ff14e243a8a8baea327440bc8cc2e32), [`276246e`](https://github.com/mastra-ai/mastra/commit/276246e0b9066a1ea48bbc70df84dbe528daaf99), [`08ecfdb`](https://github.com/mastra-ai/mastra/commit/08ecfdbdad6fb8285deef86a034bdf4a6047cfca), [`524c0f3`](https://github.com/mastra-ai/mastra/commit/524c0f3c434c3d9d18f66338dcef383d6161b59c), [`3c6ef79`](https://github.com/mastra-ai/mastra/commit/3c6ef798481e00d6d22563be2de98818fd4dd5e0), [`9311c17`](https://github.com/mastra-ai/mastra/commit/9311c17d7a0640d9c4da2e71b814dc67c57c6369), [`d25b9ea`](https://github.com/mastra-ai/mastra/commit/d25b9eabd400167255a97b690ffbc4ee4097ded5), [`b03c0e0`](https://github.com/mastra-ai/mastra/commit/b03c0e0389a799523929a458b0509c9e4244d562), [`9257d01`](https://github.com/mastra-ai/mastra/commit/9257d01d1366d81f84c582fe02b5e200cf9621f4), [`0c33b2c`](https://github.com/mastra-ai/mastra/commit/0c33b2c9db537f815e1c59e2c898ffce2e395a79), [`191e5bd`](https://github.com/mastra-ai/mastra/commit/191e5bd29b82f5bda35243945790da7bc7b695c2), [`257d14f`](https://github.com/mastra-ai/mastra/commit/257d14faca5931f2e4186fc165b6f0b1f915deee), [`31c78b3`](https://github.com/mastra-ai/mastra/commit/31c78b3eb28f58a8017f1dcc795c33214d87feac), [`3c6ef79`](https://github.com/mastra-ai/mastra/commit/3c6ef798481e00d6d22563be2de98818fd4dd5e0), [`9257d01`](https://github.com/mastra-ai/mastra/commit/9257d01d1366d81f84c582fe02b5e200cf9621f4)]:
8
+ - @mastra/core@0.0.0-auth-combined-test-all-20260302225441
package/LICENSE.md ADDED
@@ -0,0 +1,30 @@
1
+ Portions of this software are licensed as follows:
2
+
3
+ - All content that resides under any directory named "ee/" within this
4
+ repository, including but not limited to:
5
+ - `packages/core/src/auth/ee/`
6
+ - `packages/server/src/server/auth/ee/`
7
+ is licensed under the license defined in `ee/LICENSE`.
8
+
9
+ - All third-party components incorporated into the Mastra Software are
10
+ licensed under the original license provided by the owner of the
11
+ applicable component.
12
+
13
+ - Content outside of the above-mentioned directories or restrictions is
14
+ available under the "Apache License 2.0" as defined below.
15
+
16
+ # Apache License 2.0
17
+
18
+ Copyright (c) 2025 Kepler Software, Inc.
19
+
20
+ Licensed under the Apache License, Version 2.0 (the "License");
21
+ you may not use this file except in compliance with the License.
22
+ You may obtain a copy of the License at
23
+
24
+ http://www.apache.org/licenses/LICENSE-2.0
25
+
26
+ Unless required by applicable law or agreed to in writing, software
27
+ distributed under the License is distributed on an "AS IS" BASIS,
28
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29
+ See the License for the specific language governing permissions and
30
+ limitations under the License.
package/dist/index.cjs ADDED
@@ -0,0 +1,309 @@
1
+ 'use strict';
2
+
3
+ var ee = require('@mastra/core/auth/ee');
4
+ var server = require('@mastra/core/server');
5
+
6
+ // src/index.ts
7
+ var COOKIE_NAME = "wos-session";
8
+ var MastraAuthStudio = class extends server.MastraAuthProvider {
9
+ isMastraCloudAuth = true;
10
+ sharedApiUrl;
11
+ organizationId;
12
+ useProductionCookies;
13
+ constructor(options) {
14
+ super({ name: "mastra-studio", ...options });
15
+ this.sharedApiUrl = options?.sharedApiUrl || process.env.MASTRA_SHARED_API_URL || "http://localhost:3010/v1";
16
+ this.organizationId = options?.organizationId || process.env.MASTRA_ORGANIZATION_ID;
17
+ if (this.sharedApiUrl.endsWith("/")) {
18
+ this.sharedApiUrl = this.sharedApiUrl.slice(0, -1);
19
+ }
20
+ this.useProductionCookies = this.sharedApiUrl.includes(".mastra.ai");
21
+ if (options) {
22
+ this.registerOptions(options);
23
+ }
24
+ }
25
+ // ---------------------------------------------------------------------------
26
+ // MastraAuthProvider abstract methods
27
+ // ---------------------------------------------------------------------------
28
+ /**
29
+ * Authenticate an incoming request by forwarding the sealed session cookie
30
+ * to the shared API's /auth/me endpoint, or a Bearer token to /auth/verify.
31
+ */
32
+ async authenticateToken(token, request) {
33
+ let user = null;
34
+ const cookieHeader = request?.headers?.get("Cookie");
35
+ const sessionCookie = parseCookie(cookieHeader, COOKIE_NAME);
36
+ if (sessionCookie) {
37
+ user = await this.verifySessionCookie(sessionCookie);
38
+ }
39
+ if (!user && token) {
40
+ user = await this.verifyBearerToken(token);
41
+ }
42
+ if (!user) return null;
43
+ if (this.organizationId && user.organizationId !== this.organizationId) {
44
+ return null;
45
+ }
46
+ return user;
47
+ }
48
+ authorizeUser(user) {
49
+ return !!user?.id;
50
+ }
51
+ // ---------------------------------------------------------------------------
52
+ // ISSOProvider
53
+ // ---------------------------------------------------------------------------
54
+ getLoginUrl(redirectUri, state) {
55
+ let postLoginRedirect = "/";
56
+ if (state) {
57
+ const pipeIndex = state.indexOf("|");
58
+ if (pipeIndex !== -1) {
59
+ try {
60
+ postLoginRedirect = decodeURIComponent(state.slice(pipeIndex + 1));
61
+ } catch {
62
+ }
63
+ }
64
+ }
65
+ const params = new URLSearchParams({
66
+ product: "deploy",
67
+ redirect_uri: redirectUri,
68
+ post_login_redirect: postLoginRedirect,
69
+ // Force re-authentication so AuthKit always shows the account picker
70
+ prompt: "login",
71
+ ...this.organizationId ? { organization_id: this.organizationId } : {}
72
+ });
73
+ return `${this.sharedApiUrl}/auth/login?${params.toString()}`;
74
+ }
75
+ async handleCallback(code, state) {
76
+ const url = `${this.sharedApiUrl}/auth/callback?code=${encodeURIComponent(code)}&state=${encodeURIComponent(state)}`;
77
+ const res = await fetch(url, {
78
+ redirect: "manual"
79
+ });
80
+ const setCookieHeaders = res.headers.getSetCookie?.() ?? [];
81
+ const sessionValue = extractCookieValue(setCookieHeaders, COOKIE_NAME);
82
+ if (!sessionValue) {
83
+ throw new Error("No session cookie returned from callback");
84
+ }
85
+ const user = await this.verifySessionCookie(sessionValue);
86
+ if (!user) {
87
+ throw new Error("Session validation failed after callback");
88
+ }
89
+ return {
90
+ user,
91
+ tokens: {
92
+ accessToken: sessionValue
93
+ },
94
+ cookies: setCookieHeaders
95
+ };
96
+ }
97
+ setCallbackCookieHeader(_cookieHeader) {
98
+ }
99
+ getLoginCookies() {
100
+ return void 0;
101
+ }
102
+ getLoginButtonConfig() {
103
+ return {
104
+ provider: "mastra-studio",
105
+ text: "Sign in with Mastra"
106
+ };
107
+ }
108
+ async getLogoutUrl(_redirectUri, request) {
109
+ const cookieHeader = request?.headers.get("Cookie");
110
+ const sessionCookie = parseCookie(cookieHeader, COOKIE_NAME);
111
+ if (!sessionCookie) return null;
112
+ try {
113
+ const res = await fetch(`${this.sharedApiUrl}/auth/logout`, {
114
+ method: "POST",
115
+ headers: {
116
+ "Content-Type": "application/json",
117
+ Cookie: `${COOKIE_NAME}=${sessionCookie}`
118
+ }
119
+ });
120
+ if (res.ok) {
121
+ const data = await res.json();
122
+ return data.logoutUrl ?? null;
123
+ }
124
+ } catch {
125
+ }
126
+ return null;
127
+ }
128
+ // ---------------------------------------------------------------------------
129
+ // ISessionProvider
130
+ // ---------------------------------------------------------------------------
131
+ async createSession(userId, metadata) {
132
+ const now = /* @__PURE__ */ new Date();
133
+ return {
134
+ id: metadata?.accessToken || crypto.randomUUID(),
135
+ userId,
136
+ expiresAt: new Date(now.getTime() + 24 * 60 * 60 * 1e3),
137
+ // 24 hours
138
+ createdAt: now,
139
+ metadata
140
+ };
141
+ }
142
+ async validateSession(sessionId) {
143
+ const user = await this.verifySessionCookie(sessionId);
144
+ if (!user) return null;
145
+ const now = /* @__PURE__ */ new Date();
146
+ return {
147
+ id: sessionId,
148
+ userId: user.id,
149
+ expiresAt: new Date(now.getTime() + 24 * 60 * 60 * 1e3),
150
+ createdAt: now
151
+ };
152
+ }
153
+ async destroySession(sessionId) {
154
+ try {
155
+ await fetch(`${this.sharedApiUrl}/auth/logout`, {
156
+ method: "POST",
157
+ headers: {
158
+ Cookie: `${COOKIE_NAME}=${sessionId}`
159
+ }
160
+ });
161
+ } catch {
162
+ }
163
+ }
164
+ async refreshSession(sessionId) {
165
+ return this.validateSession(sessionId);
166
+ }
167
+ getSessionIdFromRequest(request) {
168
+ const cookieHeader = request.headers.get("Cookie");
169
+ return parseCookie(cookieHeader, COOKIE_NAME);
170
+ }
171
+ getSessionHeaders(session) {
172
+ const parts = [`${COOKIE_NAME}=${session.id}`, "HttpOnly", "SameSite=Lax", "Path=/", "Max-Age=86400"];
173
+ if (this.useProductionCookies) {
174
+ parts.push("Secure");
175
+ parts.push("Domain=.mastra.ai");
176
+ }
177
+ return { "Set-Cookie": parts.join("; ") };
178
+ }
179
+ getClearSessionHeaders() {
180
+ const parts = [`${COOKIE_NAME}=`, "HttpOnly", "SameSite=Lax", "Path=/", "Max-Age=0"];
181
+ if (this.useProductionCookies) {
182
+ parts.push("Secure");
183
+ parts.push("Domain=.mastra.ai");
184
+ }
185
+ return { "Set-Cookie": parts.join("; ") };
186
+ }
187
+ // ---------------------------------------------------------------------------
188
+ // IUserProvider
189
+ // ---------------------------------------------------------------------------
190
+ async getCurrentUser(request) {
191
+ const cookieHeader = request.headers.get("Cookie");
192
+ const sessionCookie = parseCookie(cookieHeader, COOKIE_NAME);
193
+ if (sessionCookie) {
194
+ return this.verifySessionCookie(sessionCookie);
195
+ }
196
+ const authHeader = request.headers.get("Authorization");
197
+ if (authHeader?.startsWith("Bearer ")) {
198
+ return this.verifyBearerToken(authHeader.slice(7));
199
+ }
200
+ return null;
201
+ }
202
+ async getUser(_userId) {
203
+ return null;
204
+ }
205
+ // ---------------------------------------------------------------------------
206
+ // Internal helpers
207
+ // ---------------------------------------------------------------------------
208
+ /**
209
+ * Forward a sealed session cookie to the shared API's /auth/me endpoint
210
+ * to validate it and get user info.
211
+ */
212
+ async verifySessionCookie(sessionCookie) {
213
+ try {
214
+ const res = await fetch(`${this.sharedApiUrl}/auth/me`, {
215
+ headers: {
216
+ Cookie: `${COOKIE_NAME}=${sessionCookie}`
217
+ }
218
+ });
219
+ if (!res.ok) return null;
220
+ const data = await res.json();
221
+ return {
222
+ id: data.user.id,
223
+ email: data.user.email,
224
+ name: [data.user.firstName, data.user.lastName].filter(Boolean).join(" ") || void 0,
225
+ avatarUrl: data.user.profilePictureUrl,
226
+ organizationId: data.organizationId,
227
+ role: data.role,
228
+ permissions: data.permissions
229
+ };
230
+ } catch {
231
+ return null;
232
+ }
233
+ }
234
+ /**
235
+ * Forward a Bearer token to the shared API's /auth/verify endpoint
236
+ * to validate it and get user info (used for CLI tokens).
237
+ */
238
+ async verifyBearerToken(token) {
239
+ try {
240
+ const res = await fetch(`${this.sharedApiUrl}/auth/verify`, {
241
+ headers: {
242
+ Authorization: `Bearer ${token}`
243
+ }
244
+ });
245
+ if (!res.ok) return null;
246
+ const data = await res.json();
247
+ return {
248
+ id: data.user.id,
249
+ email: data.user.email,
250
+ name: [data.user.firstName, data.user.lastName].filter(Boolean).join(" ") || void 0,
251
+ organizationId: data.organizationId
252
+ };
253
+ } catch {
254
+ return null;
255
+ }
256
+ }
257
+ };
258
+ function parseCookie(cookieHeader, name) {
259
+ if (!cookieHeader) return null;
260
+ const match = cookieHeader.match(new RegExp(`${name}=([^;]+)`));
261
+ return match?.[1] ?? null;
262
+ }
263
+ function extractCookieValue(setCookieHeaders, name) {
264
+ for (const header of setCookieHeaders) {
265
+ const match = header.match(new RegExp(`^${name}=([^;]+)`));
266
+ if (match?.[1]) return match[1];
267
+ }
268
+ return null;
269
+ }
270
+ var MastraRBACStudio = class {
271
+ options;
272
+ get roleMapping() {
273
+ return this.options.roleMapping;
274
+ }
275
+ constructor(options) {
276
+ this.options = options;
277
+ }
278
+ async getRoles(user) {
279
+ return user.role ? [user.role] : [];
280
+ }
281
+ async hasRole(user, role) {
282
+ const roles = await this.getRoles(user);
283
+ return roles.includes(role);
284
+ }
285
+ async getPermissions(user) {
286
+ const roles = await this.getRoles(user);
287
+ if (roles.length === 0) {
288
+ return this.options.roleMapping["_default"] ?? [];
289
+ }
290
+ return ee.resolvePermissionsFromMapping(roles, this.options.roleMapping);
291
+ }
292
+ async hasPermission(user, permission) {
293
+ const permissions = await this.getPermissions(user);
294
+ return permissions.some((p) => ee.matchesPermission(p, permission));
295
+ }
296
+ async hasAllPermissions(user, permissions) {
297
+ const userPermissions = await this.getPermissions(user);
298
+ return permissions.every((required) => userPermissions.some((p) => ee.matchesPermission(p, required)));
299
+ }
300
+ async hasAnyPermission(user, permissions) {
301
+ const userPermissions = await this.getPermissions(user);
302
+ return permissions.some((required) => userPermissions.some((p) => ee.matchesPermission(p, required)));
303
+ }
304
+ };
305
+
306
+ exports.MastraAuthStudio = MastraAuthStudio;
307
+ exports.MastraRBACStudio = MastraRBACStudio;
308
+ //# sourceMappingURL=index.cjs.map
309
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":["MastraAuthProvider","resolvePermissionsFromMapping","matchesPermission"],"mappings":"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","file":"index.cjs","sourcesContent":["import type {\n ISSOProvider,\n ISessionProvider,\n IUserProvider,\n Session,\n SSOCallbackResult,\n SSOLoginConfig,\n} from '@mastra/core/auth';\nimport type { EEUser, IRBACProvider, RoleMapping } from '@mastra/core/auth/ee';\nimport { resolvePermissionsFromMapping, matchesPermission } from '@mastra/core/auth/ee';\nimport { MastraAuthProvider } from '@mastra/core/server';\nimport type { MastraAuthProviderOptions } from '@mastra/core/server';\n\nexport interface StudioUser extends EEUser {\n id: string;\n email?: string;\n name?: string;\n avatarUrl?: string;\n organizationId?: string;\n role?: string;\n permissions?: string[];\n}\n\nexport interface MastraAuthStudioOptions extends MastraAuthProviderOptions<StudioUser> {\n /** Base URL of the Mastra shared API (e.g., https://api.mastra.ai/v1) */\n sharedApiUrl?: string;\n /** Organization ID that owns this deployed instance. Users not in this org are rejected. */\n organizationId?: string;\n}\n\nconst COOKIE_NAME = 'wos-session';\n\n/**\n * Auth provider for Mastra Studio deployed instances.\n *\n * Proxies all authentication through the shared API, keeping the\n * WorkOS API key safely in the shared API. Deployed instances only\n * need the shared API URL — no secrets required.\n *\n * The shared API's sealed session cookie (`wos-session`) is set with\n * `Domain=.mastra.ai` in production, so it's included in requests\n * to deployed instances and can be forwarded for validation.\n */\nexport class MastraAuthStudio\n extends MastraAuthProvider<StudioUser>\n implements ISSOProvider<StudioUser>, ISessionProvider<Session>, IUserProvider<StudioUser>\n{\n readonly isMastraCloudAuth = true;\n\n private sharedApiUrl: string;\n private organizationId: string | undefined;\n private useProductionCookies: boolean;\n\n constructor(options?: MastraAuthStudioOptions) {\n super({ name: 'mastra-studio', ...options });\n this.sharedApiUrl = options?.sharedApiUrl || process.env.MASTRA_SHARED_API_URL || 'http://localhost:3010/v1';\n this.organizationId = options?.organizationId || process.env.MASTRA_ORGANIZATION_ID;\n\n // Strip trailing slash\n if (this.sharedApiUrl.endsWith('/')) {\n this.sharedApiUrl = this.sharedApiUrl.slice(0, -1);\n }\n\n // Use production cookie settings (Secure + Domain=.mastra.ai) only when\n // the shared API is actually on .mastra.ai — NOT based on NODE_ENV which\n // may be 'production' even in local dev (e.g. mastra dev sets it).\n this.useProductionCookies = this.sharedApiUrl.includes('.mastra.ai');\n\n if (options) {\n this.registerOptions(options);\n }\n }\n\n // ---------------------------------------------------------------------------\n // MastraAuthProvider abstract methods\n // ---------------------------------------------------------------------------\n\n /**\n * Authenticate an incoming request by forwarding the sealed session cookie\n * to the shared API's /auth/me endpoint, or a Bearer token to /auth/verify.\n */\n async authenticateToken(token: string, request: any): Promise<StudioUser | null> {\n let user: StudioUser | null = null;\n\n // Try sealed session cookie first (browser flow)\n const cookieHeader = request?.headers?.get('Cookie');\n const sessionCookie = parseCookie(cookieHeader, COOKIE_NAME);\n\n if (sessionCookie) {\n user = await this.verifySessionCookie(sessionCookie);\n }\n\n // Fall back to Bearer token (CLI / API token flow)\n if (!user && token) {\n user = await this.verifyBearerToken(token);\n }\n\n if (!user) return null;\n\n // Org-scoping: if this instance belongs to a specific org, reject users not in that org\n if (this.organizationId && user.organizationId !== this.organizationId) {\n return null;\n }\n\n return user;\n }\n\n authorizeUser(user: StudioUser): boolean {\n return !!user?.id;\n }\n\n // ---------------------------------------------------------------------------\n // ISSOProvider\n // ---------------------------------------------------------------------------\n\n getLoginUrl(redirectUri: string, state: string): string {\n // Extract the post-login redirect from state (format: uuid|encodedPostLoginRedirect)\n let postLoginRedirect = '/';\n if (state) {\n const pipeIndex = state.indexOf('|');\n if (pipeIndex !== -1) {\n try {\n postLoginRedirect = decodeURIComponent(state.slice(pipeIndex + 1));\n } catch {\n // ignore decode errors\n }\n }\n }\n\n const params = new URLSearchParams({\n product: 'deploy',\n redirect_uri: redirectUri,\n post_login_redirect: postLoginRedirect,\n // Force re-authentication so AuthKit always shows the account picker\n prompt: 'login',\n ...(this.organizationId ? { organization_id: this.organizationId } : {}),\n });\n\n return `${this.sharedApiUrl}/auth/login?${params.toString()}`;\n }\n\n async handleCallback(code: string, state: string): Promise<SSOCallbackResult<StudioUser>> {\n // Forward the callback to the shared API\n const url = `${this.sharedApiUrl}/auth/callback?code=${encodeURIComponent(code)}&state=${encodeURIComponent(state)}`;\n\n const res = await fetch(url, {\n redirect: 'manual',\n });\n\n // The shared API redirects after setting cookies — extract the session cookie\n const setCookieHeaders = res.headers.getSetCookie?.() ?? [];\n const sessionValue = extractCookieValue(setCookieHeaders, COOKIE_NAME);\n\n if (!sessionValue) {\n throw new Error('No session cookie returned from callback');\n }\n\n // Validate the new session to get user info\n const user = await this.verifySessionCookie(sessionValue);\n if (!user) {\n throw new Error('Session validation failed after callback');\n }\n\n return {\n user,\n tokens: {\n accessToken: sessionValue,\n },\n cookies: setCookieHeaders,\n };\n }\n\n setCallbackCookieHeader(_cookieHeader: string | null): void {\n // No-op: we don't use PKCE cookies — the shared API handles the full OAuth flow\n }\n\n getLoginCookies(): string[] | undefined {\n // No PKCE cookies needed — shared API manages the OAuth state\n return undefined;\n }\n\n getLoginButtonConfig(): SSOLoginConfig {\n return {\n provider: 'mastra-studio',\n text: 'Sign in with Mastra',\n };\n }\n\n async getLogoutUrl(_redirectUri: string, request?: Request): Promise<string | null> {\n const cookieHeader = request?.headers.get('Cookie');\n const sessionCookie = parseCookie(cookieHeader, COOKIE_NAME);\n\n if (!sessionCookie) return null;\n\n try {\n const res = await fetch(`${this.sharedApiUrl}/auth/logout`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Cookie: `${COOKIE_NAME}=${sessionCookie}`,\n },\n });\n\n if (res.ok) {\n const data = (await res.json()) as { ok: boolean; logoutUrl?: string };\n return data.logoutUrl ?? null;\n }\n } catch {\n // Failed to get logout URL — return null\n }\n\n return null;\n }\n\n // ---------------------------------------------------------------------------\n // ISessionProvider\n // ---------------------------------------------------------------------------\n\n async createSession(userId: string, metadata?: Record<string, unknown>): Promise<Session> {\n const now = new Date();\n return {\n id: (metadata?.accessToken as string) || crypto.randomUUID(),\n userId,\n expiresAt: new Date(now.getTime() + 24 * 60 * 60 * 1000), // 24 hours\n createdAt: now,\n metadata,\n };\n }\n\n async validateSession(sessionId: string): Promise<Session | null> {\n const user = await this.verifySessionCookie(sessionId);\n if (!user) return null;\n\n const now = new Date();\n return {\n id: sessionId,\n userId: user.id,\n expiresAt: new Date(now.getTime() + 24 * 60 * 60 * 1000),\n createdAt: now,\n };\n }\n\n async destroySession(sessionId: string): Promise<void> {\n try {\n await fetch(`${this.sharedApiUrl}/auth/logout`, {\n method: 'POST',\n headers: {\n Cookie: `${COOKIE_NAME}=${sessionId}`,\n },\n });\n } catch {\n // Best effort\n }\n }\n\n async refreshSession(sessionId: string): Promise<Session | null> {\n return this.validateSession(sessionId);\n }\n\n getSessionIdFromRequest(request: Request): string | null {\n const cookieHeader = request.headers.get('Cookie');\n return parseCookie(cookieHeader, COOKIE_NAME);\n }\n\n getSessionHeaders(session: Session): Record<string, string> {\n const parts = [`${COOKIE_NAME}=${session.id}`, 'HttpOnly', 'SameSite=Lax', 'Path=/', 'Max-Age=86400'];\n if (this.useProductionCookies) {\n parts.push('Secure');\n parts.push('Domain=.mastra.ai');\n }\n return { 'Set-Cookie': parts.join('; ') };\n }\n\n getClearSessionHeaders(): Record<string, string> {\n const parts = [`${COOKIE_NAME}=`, 'HttpOnly', 'SameSite=Lax', 'Path=/', 'Max-Age=0'];\n if (this.useProductionCookies) {\n parts.push('Secure');\n parts.push('Domain=.mastra.ai');\n }\n return { 'Set-Cookie': parts.join('; ') };\n }\n\n // ---------------------------------------------------------------------------\n // IUserProvider\n // ---------------------------------------------------------------------------\n\n async getCurrentUser(request: Request): Promise<StudioUser | null> {\n const cookieHeader = request.headers.get('Cookie');\n const sessionCookie = parseCookie(cookieHeader, COOKIE_NAME);\n\n if (sessionCookie) {\n return this.verifySessionCookie(sessionCookie);\n }\n\n // Try bearer token\n const authHeader = request.headers.get('Authorization');\n if (authHeader?.startsWith('Bearer ')) {\n return this.verifyBearerToken(authHeader.slice(7));\n }\n\n return null;\n }\n\n async getUser(_userId: string): Promise<StudioUser | null> {\n // Cannot look up users by ID — only validate sessions\n return null;\n }\n\n // ---------------------------------------------------------------------------\n // Internal helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Forward a sealed session cookie to the shared API's /auth/me endpoint\n * to validate it and get user info.\n */\n private async verifySessionCookie(sessionCookie: string): Promise<StudioUser | null> {\n try {\n const res = await fetch(`${this.sharedApiUrl}/auth/me`, {\n headers: {\n Cookie: `${COOKIE_NAME}=${sessionCookie}`,\n },\n });\n\n if (!res.ok) return null;\n\n const data = (await res.json()) as {\n user: {\n id: string;\n email: string;\n firstName: string;\n lastName: string;\n profilePictureUrl?: string;\n };\n organizationId: string;\n role?: string;\n permissions?: string[];\n };\n\n return {\n id: data.user.id,\n email: data.user.email,\n name: [data.user.firstName, data.user.lastName].filter(Boolean).join(' ') || undefined,\n avatarUrl: data.user.profilePictureUrl,\n organizationId: data.organizationId,\n role: data.role,\n permissions: data.permissions,\n };\n } catch {\n return null;\n }\n }\n\n /**\n * Forward a Bearer token to the shared API's /auth/verify endpoint\n * to validate it and get user info (used for CLI tokens).\n */\n private async verifyBearerToken(token: string): Promise<StudioUser | null> {\n try {\n const res = await fetch(`${this.sharedApiUrl}/auth/verify`, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!res.ok) return null;\n\n const data = (await res.json()) as {\n user: {\n id: string;\n email: string;\n firstName: string;\n lastName: string;\n };\n organizationId: string;\n };\n\n return {\n id: data.user.id,\n email: data.user.email,\n name: [data.user.firstName, data.user.lastName].filter(Boolean).join(' ') || undefined,\n organizationId: data.organizationId,\n };\n } catch {\n return null;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Cookie helpers\n// ---------------------------------------------------------------------------\n\nfunction parseCookie(cookieHeader: string | null | undefined, name: string): string | null {\n if (!cookieHeader) return null;\n const match = cookieHeader.match(new RegExp(`${name}=([^;]+)`));\n return match?.[1] ?? null;\n}\n\nfunction extractCookieValue(setCookieHeaders: string[], name: string): string | null {\n for (const header of setCookieHeaders) {\n const match = header.match(new RegExp(`^${name}=([^;]+)`));\n if (match?.[1]) return match[1];\n }\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// MastraRBACStudio — role-based permission provider for Studio auth\n// ---------------------------------------------------------------------------\n\nexport interface MastraRBACStudioOptions {\n /**\n * Mapping from role names to permission arrays.\n *\n * @example\n * ```typescript\n * {\n * admin: ['*'],\n * member: ['agents:read', 'workflows:*'],\n * viewer: ['agents:read', 'workflows:read'],\n * _default: [],\n * }\n * ```\n */\n roleMapping: RoleMapping;\n}\n\n/**\n * RBAC provider for Mastra Studio authentication.\n *\n * Maps user roles (from the shared API's /auth/me endpoint) to Mastra permissions\n * using a configurable role mapping.\n */\nexport class MastraRBACStudio implements IRBACProvider<StudioUser> {\n private options: MastraRBACStudioOptions;\n\n get roleMapping(): RoleMapping {\n return this.options.roleMapping;\n }\n\n constructor(options: MastraRBACStudioOptions) {\n this.options = options;\n }\n\n async getRoles(user: StudioUser): Promise<string[]> {\n return user.role ? [user.role] : [];\n }\n\n async hasRole(user: StudioUser, role: string): Promise<boolean> {\n const roles = await this.getRoles(user);\n return roles.includes(role);\n }\n\n async getPermissions(user: StudioUser): Promise<string[]> {\n const roles = await this.getRoles(user);\n if (roles.length === 0) {\n return this.options.roleMapping['_default'] ?? [];\n }\n return resolvePermissionsFromMapping(roles, this.options.roleMapping);\n }\n\n async hasPermission(user: StudioUser, permission: string): Promise<boolean> {\n const permissions = await this.getPermissions(user);\n return permissions.some(p => matchesPermission(p, permission));\n }\n\n async hasAllPermissions(user: StudioUser, permissions: string[]): Promise<boolean> {\n const userPermissions = await this.getPermissions(user);\n return permissions.every(required => userPermissions.some(p => matchesPermission(p, required)));\n }\n\n async hasAnyPermission(user: StudioUser, permissions: string[]): Promise<boolean> {\n const userPermissions = await this.getPermissions(user);\n return permissions.some(required => userPermissions.some(p => matchesPermission(p, required)));\n }\n}\n"]}
@@ -0,0 +1,102 @@
1
+ import type { ISSOProvider, ISessionProvider, IUserProvider, Session, SSOCallbackResult, SSOLoginConfig } from '@mastra/core/auth';
2
+ import type { EEUser, IRBACProvider, RoleMapping } from '@mastra/core/auth/ee';
3
+ import { MastraAuthProvider } from '@mastra/core/server';
4
+ import type { MastraAuthProviderOptions } from '@mastra/core/server';
5
+ export interface StudioUser extends EEUser {
6
+ id: string;
7
+ email?: string;
8
+ name?: string;
9
+ avatarUrl?: string;
10
+ organizationId?: string;
11
+ role?: string;
12
+ permissions?: string[];
13
+ }
14
+ export interface MastraAuthStudioOptions extends MastraAuthProviderOptions<StudioUser> {
15
+ /** Base URL of the Mastra shared API (e.g., https://api.mastra.ai/v1) */
16
+ sharedApiUrl?: string;
17
+ /** Organization ID that owns this deployed instance. Users not in this org are rejected. */
18
+ organizationId?: string;
19
+ }
20
+ /**
21
+ * Auth provider for Mastra Studio deployed instances.
22
+ *
23
+ * Proxies all authentication through the shared API, keeping the
24
+ * WorkOS API key safely in the shared API. Deployed instances only
25
+ * need the shared API URL — no secrets required.
26
+ *
27
+ * The shared API's sealed session cookie (`wos-session`) is set with
28
+ * `Domain=.mastra.ai` in production, so it's included in requests
29
+ * to deployed instances and can be forwarded for validation.
30
+ */
31
+ export declare class MastraAuthStudio extends MastraAuthProvider<StudioUser> implements ISSOProvider<StudioUser>, ISessionProvider<Session>, IUserProvider<StudioUser> {
32
+ readonly isMastraCloudAuth = true;
33
+ private sharedApiUrl;
34
+ private organizationId;
35
+ private useProductionCookies;
36
+ constructor(options?: MastraAuthStudioOptions);
37
+ /**
38
+ * Authenticate an incoming request by forwarding the sealed session cookie
39
+ * to the shared API's /auth/me endpoint, or a Bearer token to /auth/verify.
40
+ */
41
+ authenticateToken(token: string, request: any): Promise<StudioUser | null>;
42
+ authorizeUser(user: StudioUser): boolean;
43
+ getLoginUrl(redirectUri: string, state: string): string;
44
+ handleCallback(code: string, state: string): Promise<SSOCallbackResult<StudioUser>>;
45
+ setCallbackCookieHeader(_cookieHeader: string | null): void;
46
+ getLoginCookies(): string[] | undefined;
47
+ getLoginButtonConfig(): SSOLoginConfig;
48
+ getLogoutUrl(_redirectUri: string, request?: Request): Promise<string | null>;
49
+ createSession(userId: string, metadata?: Record<string, unknown>): Promise<Session>;
50
+ validateSession(sessionId: string): Promise<Session | null>;
51
+ destroySession(sessionId: string): Promise<void>;
52
+ refreshSession(sessionId: string): Promise<Session | null>;
53
+ getSessionIdFromRequest(request: Request): string | null;
54
+ getSessionHeaders(session: Session): Record<string, string>;
55
+ getClearSessionHeaders(): Record<string, string>;
56
+ getCurrentUser(request: Request): Promise<StudioUser | null>;
57
+ getUser(_userId: string): Promise<StudioUser | null>;
58
+ /**
59
+ * Forward a sealed session cookie to the shared API's /auth/me endpoint
60
+ * to validate it and get user info.
61
+ */
62
+ private verifySessionCookie;
63
+ /**
64
+ * Forward a Bearer token to the shared API's /auth/verify endpoint
65
+ * to validate it and get user info (used for CLI tokens).
66
+ */
67
+ private verifyBearerToken;
68
+ }
69
+ export interface MastraRBACStudioOptions {
70
+ /**
71
+ * Mapping from role names to permission arrays.
72
+ *
73
+ * @example
74
+ * ```typescript
75
+ * {
76
+ * admin: ['*'],
77
+ * member: ['agents:read', 'workflows:*'],
78
+ * viewer: ['agents:read', 'workflows:read'],
79
+ * _default: [],
80
+ * }
81
+ * ```
82
+ */
83
+ roleMapping: RoleMapping;
84
+ }
85
+ /**
86
+ * RBAC provider for Mastra Studio authentication.
87
+ *
88
+ * Maps user roles (from the shared API's /auth/me endpoint) to Mastra permissions
89
+ * using a configurable role mapping.
90
+ */
91
+ export declare class MastraRBACStudio implements IRBACProvider<StudioUser> {
92
+ private options;
93
+ get roleMapping(): RoleMapping;
94
+ constructor(options: MastraRBACStudioOptions);
95
+ getRoles(user: StudioUser): Promise<string[]>;
96
+ hasRole(user: StudioUser, role: string): Promise<boolean>;
97
+ getPermissions(user: StudioUser): Promise<string[]>;
98
+ hasPermission(user: StudioUser, permission: string): Promise<boolean>;
99
+ hasAllPermissions(user: StudioUser, permissions: string[]): Promise<boolean>;
100
+ hasAnyPermission(user: StudioUser, permissions: string[]): Promise<boolean>;
101
+ }
102
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,306 @@
1
+ import { resolvePermissionsFromMapping, matchesPermission } from '@mastra/core/auth/ee';
2
+ import { MastraAuthProvider } from '@mastra/core/server';
3
+
4
+ // src/index.ts
5
+ var COOKIE_NAME = "wos-session";
6
+ var MastraAuthStudio = class extends MastraAuthProvider {
7
+ isMastraCloudAuth = true;
8
+ sharedApiUrl;
9
+ organizationId;
10
+ useProductionCookies;
11
+ constructor(options) {
12
+ super({ name: "mastra-studio", ...options });
13
+ this.sharedApiUrl = options?.sharedApiUrl || process.env.MASTRA_SHARED_API_URL || "http://localhost:3010/v1";
14
+ this.organizationId = options?.organizationId || process.env.MASTRA_ORGANIZATION_ID;
15
+ if (this.sharedApiUrl.endsWith("/")) {
16
+ this.sharedApiUrl = this.sharedApiUrl.slice(0, -1);
17
+ }
18
+ this.useProductionCookies = this.sharedApiUrl.includes(".mastra.ai");
19
+ if (options) {
20
+ this.registerOptions(options);
21
+ }
22
+ }
23
+ // ---------------------------------------------------------------------------
24
+ // MastraAuthProvider abstract methods
25
+ // ---------------------------------------------------------------------------
26
+ /**
27
+ * Authenticate an incoming request by forwarding the sealed session cookie
28
+ * to the shared API's /auth/me endpoint, or a Bearer token to /auth/verify.
29
+ */
30
+ async authenticateToken(token, request) {
31
+ let user = null;
32
+ const cookieHeader = request?.headers?.get("Cookie");
33
+ const sessionCookie = parseCookie(cookieHeader, COOKIE_NAME);
34
+ if (sessionCookie) {
35
+ user = await this.verifySessionCookie(sessionCookie);
36
+ }
37
+ if (!user && token) {
38
+ user = await this.verifyBearerToken(token);
39
+ }
40
+ if (!user) return null;
41
+ if (this.organizationId && user.organizationId !== this.organizationId) {
42
+ return null;
43
+ }
44
+ return user;
45
+ }
46
+ authorizeUser(user) {
47
+ return !!user?.id;
48
+ }
49
+ // ---------------------------------------------------------------------------
50
+ // ISSOProvider
51
+ // ---------------------------------------------------------------------------
52
+ getLoginUrl(redirectUri, state) {
53
+ let postLoginRedirect = "/";
54
+ if (state) {
55
+ const pipeIndex = state.indexOf("|");
56
+ if (pipeIndex !== -1) {
57
+ try {
58
+ postLoginRedirect = decodeURIComponent(state.slice(pipeIndex + 1));
59
+ } catch {
60
+ }
61
+ }
62
+ }
63
+ const params = new URLSearchParams({
64
+ product: "deploy",
65
+ redirect_uri: redirectUri,
66
+ post_login_redirect: postLoginRedirect,
67
+ // Force re-authentication so AuthKit always shows the account picker
68
+ prompt: "login",
69
+ ...this.organizationId ? { organization_id: this.organizationId } : {}
70
+ });
71
+ return `${this.sharedApiUrl}/auth/login?${params.toString()}`;
72
+ }
73
+ async handleCallback(code, state) {
74
+ const url = `${this.sharedApiUrl}/auth/callback?code=${encodeURIComponent(code)}&state=${encodeURIComponent(state)}`;
75
+ const res = await fetch(url, {
76
+ redirect: "manual"
77
+ });
78
+ const setCookieHeaders = res.headers.getSetCookie?.() ?? [];
79
+ const sessionValue = extractCookieValue(setCookieHeaders, COOKIE_NAME);
80
+ if (!sessionValue) {
81
+ throw new Error("No session cookie returned from callback");
82
+ }
83
+ const user = await this.verifySessionCookie(sessionValue);
84
+ if (!user) {
85
+ throw new Error("Session validation failed after callback");
86
+ }
87
+ return {
88
+ user,
89
+ tokens: {
90
+ accessToken: sessionValue
91
+ },
92
+ cookies: setCookieHeaders
93
+ };
94
+ }
95
+ setCallbackCookieHeader(_cookieHeader) {
96
+ }
97
+ getLoginCookies() {
98
+ return void 0;
99
+ }
100
+ getLoginButtonConfig() {
101
+ return {
102
+ provider: "mastra-studio",
103
+ text: "Sign in with Mastra"
104
+ };
105
+ }
106
+ async getLogoutUrl(_redirectUri, request) {
107
+ const cookieHeader = request?.headers.get("Cookie");
108
+ const sessionCookie = parseCookie(cookieHeader, COOKIE_NAME);
109
+ if (!sessionCookie) return null;
110
+ try {
111
+ const res = await fetch(`${this.sharedApiUrl}/auth/logout`, {
112
+ method: "POST",
113
+ headers: {
114
+ "Content-Type": "application/json",
115
+ Cookie: `${COOKIE_NAME}=${sessionCookie}`
116
+ }
117
+ });
118
+ if (res.ok) {
119
+ const data = await res.json();
120
+ return data.logoutUrl ?? null;
121
+ }
122
+ } catch {
123
+ }
124
+ return null;
125
+ }
126
+ // ---------------------------------------------------------------------------
127
+ // ISessionProvider
128
+ // ---------------------------------------------------------------------------
129
+ async createSession(userId, metadata) {
130
+ const now = /* @__PURE__ */ new Date();
131
+ return {
132
+ id: metadata?.accessToken || crypto.randomUUID(),
133
+ userId,
134
+ expiresAt: new Date(now.getTime() + 24 * 60 * 60 * 1e3),
135
+ // 24 hours
136
+ createdAt: now,
137
+ metadata
138
+ };
139
+ }
140
+ async validateSession(sessionId) {
141
+ const user = await this.verifySessionCookie(sessionId);
142
+ if (!user) return null;
143
+ const now = /* @__PURE__ */ new Date();
144
+ return {
145
+ id: sessionId,
146
+ userId: user.id,
147
+ expiresAt: new Date(now.getTime() + 24 * 60 * 60 * 1e3),
148
+ createdAt: now
149
+ };
150
+ }
151
+ async destroySession(sessionId) {
152
+ try {
153
+ await fetch(`${this.sharedApiUrl}/auth/logout`, {
154
+ method: "POST",
155
+ headers: {
156
+ Cookie: `${COOKIE_NAME}=${sessionId}`
157
+ }
158
+ });
159
+ } catch {
160
+ }
161
+ }
162
+ async refreshSession(sessionId) {
163
+ return this.validateSession(sessionId);
164
+ }
165
+ getSessionIdFromRequest(request) {
166
+ const cookieHeader = request.headers.get("Cookie");
167
+ return parseCookie(cookieHeader, COOKIE_NAME);
168
+ }
169
+ getSessionHeaders(session) {
170
+ const parts = [`${COOKIE_NAME}=${session.id}`, "HttpOnly", "SameSite=Lax", "Path=/", "Max-Age=86400"];
171
+ if (this.useProductionCookies) {
172
+ parts.push("Secure");
173
+ parts.push("Domain=.mastra.ai");
174
+ }
175
+ return { "Set-Cookie": parts.join("; ") };
176
+ }
177
+ getClearSessionHeaders() {
178
+ const parts = [`${COOKIE_NAME}=`, "HttpOnly", "SameSite=Lax", "Path=/", "Max-Age=0"];
179
+ if (this.useProductionCookies) {
180
+ parts.push("Secure");
181
+ parts.push("Domain=.mastra.ai");
182
+ }
183
+ return { "Set-Cookie": parts.join("; ") };
184
+ }
185
+ // ---------------------------------------------------------------------------
186
+ // IUserProvider
187
+ // ---------------------------------------------------------------------------
188
+ async getCurrentUser(request) {
189
+ const cookieHeader = request.headers.get("Cookie");
190
+ const sessionCookie = parseCookie(cookieHeader, COOKIE_NAME);
191
+ if (sessionCookie) {
192
+ return this.verifySessionCookie(sessionCookie);
193
+ }
194
+ const authHeader = request.headers.get("Authorization");
195
+ if (authHeader?.startsWith("Bearer ")) {
196
+ return this.verifyBearerToken(authHeader.slice(7));
197
+ }
198
+ return null;
199
+ }
200
+ async getUser(_userId) {
201
+ return null;
202
+ }
203
+ // ---------------------------------------------------------------------------
204
+ // Internal helpers
205
+ // ---------------------------------------------------------------------------
206
+ /**
207
+ * Forward a sealed session cookie to the shared API's /auth/me endpoint
208
+ * to validate it and get user info.
209
+ */
210
+ async verifySessionCookie(sessionCookie) {
211
+ try {
212
+ const res = await fetch(`${this.sharedApiUrl}/auth/me`, {
213
+ headers: {
214
+ Cookie: `${COOKIE_NAME}=${sessionCookie}`
215
+ }
216
+ });
217
+ if (!res.ok) return null;
218
+ const data = await res.json();
219
+ return {
220
+ id: data.user.id,
221
+ email: data.user.email,
222
+ name: [data.user.firstName, data.user.lastName].filter(Boolean).join(" ") || void 0,
223
+ avatarUrl: data.user.profilePictureUrl,
224
+ organizationId: data.organizationId,
225
+ role: data.role,
226
+ permissions: data.permissions
227
+ };
228
+ } catch {
229
+ return null;
230
+ }
231
+ }
232
+ /**
233
+ * Forward a Bearer token to the shared API's /auth/verify endpoint
234
+ * to validate it and get user info (used for CLI tokens).
235
+ */
236
+ async verifyBearerToken(token) {
237
+ try {
238
+ const res = await fetch(`${this.sharedApiUrl}/auth/verify`, {
239
+ headers: {
240
+ Authorization: `Bearer ${token}`
241
+ }
242
+ });
243
+ if (!res.ok) return null;
244
+ const data = await res.json();
245
+ return {
246
+ id: data.user.id,
247
+ email: data.user.email,
248
+ name: [data.user.firstName, data.user.lastName].filter(Boolean).join(" ") || void 0,
249
+ organizationId: data.organizationId
250
+ };
251
+ } catch {
252
+ return null;
253
+ }
254
+ }
255
+ };
256
+ function parseCookie(cookieHeader, name) {
257
+ if (!cookieHeader) return null;
258
+ const match = cookieHeader.match(new RegExp(`${name}=([^;]+)`));
259
+ return match?.[1] ?? null;
260
+ }
261
+ function extractCookieValue(setCookieHeaders, name) {
262
+ for (const header of setCookieHeaders) {
263
+ const match = header.match(new RegExp(`^${name}=([^;]+)`));
264
+ if (match?.[1]) return match[1];
265
+ }
266
+ return null;
267
+ }
268
+ var MastraRBACStudio = class {
269
+ options;
270
+ get roleMapping() {
271
+ return this.options.roleMapping;
272
+ }
273
+ constructor(options) {
274
+ this.options = options;
275
+ }
276
+ async getRoles(user) {
277
+ return user.role ? [user.role] : [];
278
+ }
279
+ async hasRole(user, role) {
280
+ const roles = await this.getRoles(user);
281
+ return roles.includes(role);
282
+ }
283
+ async getPermissions(user) {
284
+ const roles = await this.getRoles(user);
285
+ if (roles.length === 0) {
286
+ return this.options.roleMapping["_default"] ?? [];
287
+ }
288
+ return resolvePermissionsFromMapping(roles, this.options.roleMapping);
289
+ }
290
+ async hasPermission(user, permission) {
291
+ const permissions = await this.getPermissions(user);
292
+ return permissions.some((p) => matchesPermission(p, permission));
293
+ }
294
+ async hasAllPermissions(user, permissions) {
295
+ const userPermissions = await this.getPermissions(user);
296
+ return permissions.every((required) => userPermissions.some((p) => matchesPermission(p, required)));
297
+ }
298
+ async hasAnyPermission(user, permissions) {
299
+ const userPermissions = await this.getPermissions(user);
300
+ return permissions.some((required) => userPermissions.some((p) => matchesPermission(p, required)));
301
+ }
302
+ };
303
+
304
+ export { MastraAuthStudio, MastraRBACStudio };
305
+ //# sourceMappingURL=index.js.map
306
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type {\n ISSOProvider,\n ISessionProvider,\n IUserProvider,\n Session,\n SSOCallbackResult,\n SSOLoginConfig,\n} from '@mastra/core/auth';\nimport type { EEUser, IRBACProvider, RoleMapping } from '@mastra/core/auth/ee';\nimport { resolvePermissionsFromMapping, matchesPermission } from '@mastra/core/auth/ee';\nimport { MastraAuthProvider } from '@mastra/core/server';\nimport type { MastraAuthProviderOptions } from '@mastra/core/server';\n\nexport interface StudioUser extends EEUser {\n id: string;\n email?: string;\n name?: string;\n avatarUrl?: string;\n organizationId?: string;\n role?: string;\n permissions?: string[];\n}\n\nexport interface MastraAuthStudioOptions extends MastraAuthProviderOptions<StudioUser> {\n /** Base URL of the Mastra shared API (e.g., https://api.mastra.ai/v1) */\n sharedApiUrl?: string;\n /** Organization ID that owns this deployed instance. Users not in this org are rejected. */\n organizationId?: string;\n}\n\nconst COOKIE_NAME = 'wos-session';\n\n/**\n * Auth provider for Mastra Studio deployed instances.\n *\n * Proxies all authentication through the shared API, keeping the\n * WorkOS API key safely in the shared API. Deployed instances only\n * need the shared API URL — no secrets required.\n *\n * The shared API's sealed session cookie (`wos-session`) is set with\n * `Domain=.mastra.ai` in production, so it's included in requests\n * to deployed instances and can be forwarded for validation.\n */\nexport class MastraAuthStudio\n extends MastraAuthProvider<StudioUser>\n implements ISSOProvider<StudioUser>, ISessionProvider<Session>, IUserProvider<StudioUser>\n{\n readonly isMastraCloudAuth = true;\n\n private sharedApiUrl: string;\n private organizationId: string | undefined;\n private useProductionCookies: boolean;\n\n constructor(options?: MastraAuthStudioOptions) {\n super({ name: 'mastra-studio', ...options });\n this.sharedApiUrl = options?.sharedApiUrl || process.env.MASTRA_SHARED_API_URL || 'http://localhost:3010/v1';\n this.organizationId = options?.organizationId || process.env.MASTRA_ORGANIZATION_ID;\n\n // Strip trailing slash\n if (this.sharedApiUrl.endsWith('/')) {\n this.sharedApiUrl = this.sharedApiUrl.slice(0, -1);\n }\n\n // Use production cookie settings (Secure + Domain=.mastra.ai) only when\n // the shared API is actually on .mastra.ai — NOT based on NODE_ENV which\n // may be 'production' even in local dev (e.g. mastra dev sets it).\n this.useProductionCookies = this.sharedApiUrl.includes('.mastra.ai');\n\n if (options) {\n this.registerOptions(options);\n }\n }\n\n // ---------------------------------------------------------------------------\n // MastraAuthProvider abstract methods\n // ---------------------------------------------------------------------------\n\n /**\n * Authenticate an incoming request by forwarding the sealed session cookie\n * to the shared API's /auth/me endpoint, or a Bearer token to /auth/verify.\n */\n async authenticateToken(token: string, request: any): Promise<StudioUser | null> {\n let user: StudioUser | null = null;\n\n // Try sealed session cookie first (browser flow)\n const cookieHeader = request?.headers?.get('Cookie');\n const sessionCookie = parseCookie(cookieHeader, COOKIE_NAME);\n\n if (sessionCookie) {\n user = await this.verifySessionCookie(sessionCookie);\n }\n\n // Fall back to Bearer token (CLI / API token flow)\n if (!user && token) {\n user = await this.verifyBearerToken(token);\n }\n\n if (!user) return null;\n\n // Org-scoping: if this instance belongs to a specific org, reject users not in that org\n if (this.organizationId && user.organizationId !== this.organizationId) {\n return null;\n }\n\n return user;\n }\n\n authorizeUser(user: StudioUser): boolean {\n return !!user?.id;\n }\n\n // ---------------------------------------------------------------------------\n // ISSOProvider\n // ---------------------------------------------------------------------------\n\n getLoginUrl(redirectUri: string, state: string): string {\n // Extract the post-login redirect from state (format: uuid|encodedPostLoginRedirect)\n let postLoginRedirect = '/';\n if (state) {\n const pipeIndex = state.indexOf('|');\n if (pipeIndex !== -1) {\n try {\n postLoginRedirect = decodeURIComponent(state.slice(pipeIndex + 1));\n } catch {\n // ignore decode errors\n }\n }\n }\n\n const params = new URLSearchParams({\n product: 'deploy',\n redirect_uri: redirectUri,\n post_login_redirect: postLoginRedirect,\n // Force re-authentication so AuthKit always shows the account picker\n prompt: 'login',\n ...(this.organizationId ? { organization_id: this.organizationId } : {}),\n });\n\n return `${this.sharedApiUrl}/auth/login?${params.toString()}`;\n }\n\n async handleCallback(code: string, state: string): Promise<SSOCallbackResult<StudioUser>> {\n // Forward the callback to the shared API\n const url = `${this.sharedApiUrl}/auth/callback?code=${encodeURIComponent(code)}&state=${encodeURIComponent(state)}`;\n\n const res = await fetch(url, {\n redirect: 'manual',\n });\n\n // The shared API redirects after setting cookies — extract the session cookie\n const setCookieHeaders = res.headers.getSetCookie?.() ?? [];\n const sessionValue = extractCookieValue(setCookieHeaders, COOKIE_NAME);\n\n if (!sessionValue) {\n throw new Error('No session cookie returned from callback');\n }\n\n // Validate the new session to get user info\n const user = await this.verifySessionCookie(sessionValue);\n if (!user) {\n throw new Error('Session validation failed after callback');\n }\n\n return {\n user,\n tokens: {\n accessToken: sessionValue,\n },\n cookies: setCookieHeaders,\n };\n }\n\n setCallbackCookieHeader(_cookieHeader: string | null): void {\n // No-op: we don't use PKCE cookies — the shared API handles the full OAuth flow\n }\n\n getLoginCookies(): string[] | undefined {\n // No PKCE cookies needed — shared API manages the OAuth state\n return undefined;\n }\n\n getLoginButtonConfig(): SSOLoginConfig {\n return {\n provider: 'mastra-studio',\n text: 'Sign in with Mastra',\n };\n }\n\n async getLogoutUrl(_redirectUri: string, request?: Request): Promise<string | null> {\n const cookieHeader = request?.headers.get('Cookie');\n const sessionCookie = parseCookie(cookieHeader, COOKIE_NAME);\n\n if (!sessionCookie) return null;\n\n try {\n const res = await fetch(`${this.sharedApiUrl}/auth/logout`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Cookie: `${COOKIE_NAME}=${sessionCookie}`,\n },\n });\n\n if (res.ok) {\n const data = (await res.json()) as { ok: boolean; logoutUrl?: string };\n return data.logoutUrl ?? null;\n }\n } catch {\n // Failed to get logout URL — return null\n }\n\n return null;\n }\n\n // ---------------------------------------------------------------------------\n // ISessionProvider\n // ---------------------------------------------------------------------------\n\n async createSession(userId: string, metadata?: Record<string, unknown>): Promise<Session> {\n const now = new Date();\n return {\n id: (metadata?.accessToken as string) || crypto.randomUUID(),\n userId,\n expiresAt: new Date(now.getTime() + 24 * 60 * 60 * 1000), // 24 hours\n createdAt: now,\n metadata,\n };\n }\n\n async validateSession(sessionId: string): Promise<Session | null> {\n const user = await this.verifySessionCookie(sessionId);\n if (!user) return null;\n\n const now = new Date();\n return {\n id: sessionId,\n userId: user.id,\n expiresAt: new Date(now.getTime() + 24 * 60 * 60 * 1000),\n createdAt: now,\n };\n }\n\n async destroySession(sessionId: string): Promise<void> {\n try {\n await fetch(`${this.sharedApiUrl}/auth/logout`, {\n method: 'POST',\n headers: {\n Cookie: `${COOKIE_NAME}=${sessionId}`,\n },\n });\n } catch {\n // Best effort\n }\n }\n\n async refreshSession(sessionId: string): Promise<Session | null> {\n return this.validateSession(sessionId);\n }\n\n getSessionIdFromRequest(request: Request): string | null {\n const cookieHeader = request.headers.get('Cookie');\n return parseCookie(cookieHeader, COOKIE_NAME);\n }\n\n getSessionHeaders(session: Session): Record<string, string> {\n const parts = [`${COOKIE_NAME}=${session.id}`, 'HttpOnly', 'SameSite=Lax', 'Path=/', 'Max-Age=86400'];\n if (this.useProductionCookies) {\n parts.push('Secure');\n parts.push('Domain=.mastra.ai');\n }\n return { 'Set-Cookie': parts.join('; ') };\n }\n\n getClearSessionHeaders(): Record<string, string> {\n const parts = [`${COOKIE_NAME}=`, 'HttpOnly', 'SameSite=Lax', 'Path=/', 'Max-Age=0'];\n if (this.useProductionCookies) {\n parts.push('Secure');\n parts.push('Domain=.mastra.ai');\n }\n return { 'Set-Cookie': parts.join('; ') };\n }\n\n // ---------------------------------------------------------------------------\n // IUserProvider\n // ---------------------------------------------------------------------------\n\n async getCurrentUser(request: Request): Promise<StudioUser | null> {\n const cookieHeader = request.headers.get('Cookie');\n const sessionCookie = parseCookie(cookieHeader, COOKIE_NAME);\n\n if (sessionCookie) {\n return this.verifySessionCookie(sessionCookie);\n }\n\n // Try bearer token\n const authHeader = request.headers.get('Authorization');\n if (authHeader?.startsWith('Bearer ')) {\n return this.verifyBearerToken(authHeader.slice(7));\n }\n\n return null;\n }\n\n async getUser(_userId: string): Promise<StudioUser | null> {\n // Cannot look up users by ID — only validate sessions\n return null;\n }\n\n // ---------------------------------------------------------------------------\n // Internal helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Forward a sealed session cookie to the shared API's /auth/me endpoint\n * to validate it and get user info.\n */\n private async verifySessionCookie(sessionCookie: string): Promise<StudioUser | null> {\n try {\n const res = await fetch(`${this.sharedApiUrl}/auth/me`, {\n headers: {\n Cookie: `${COOKIE_NAME}=${sessionCookie}`,\n },\n });\n\n if (!res.ok) return null;\n\n const data = (await res.json()) as {\n user: {\n id: string;\n email: string;\n firstName: string;\n lastName: string;\n profilePictureUrl?: string;\n };\n organizationId: string;\n role?: string;\n permissions?: string[];\n };\n\n return {\n id: data.user.id,\n email: data.user.email,\n name: [data.user.firstName, data.user.lastName].filter(Boolean).join(' ') || undefined,\n avatarUrl: data.user.profilePictureUrl,\n organizationId: data.organizationId,\n role: data.role,\n permissions: data.permissions,\n };\n } catch {\n return null;\n }\n }\n\n /**\n * Forward a Bearer token to the shared API's /auth/verify endpoint\n * to validate it and get user info (used for CLI tokens).\n */\n private async verifyBearerToken(token: string): Promise<StudioUser | null> {\n try {\n const res = await fetch(`${this.sharedApiUrl}/auth/verify`, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!res.ok) return null;\n\n const data = (await res.json()) as {\n user: {\n id: string;\n email: string;\n firstName: string;\n lastName: string;\n };\n organizationId: string;\n };\n\n return {\n id: data.user.id,\n email: data.user.email,\n name: [data.user.firstName, data.user.lastName].filter(Boolean).join(' ') || undefined,\n organizationId: data.organizationId,\n };\n } catch {\n return null;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Cookie helpers\n// ---------------------------------------------------------------------------\n\nfunction parseCookie(cookieHeader: string | null | undefined, name: string): string | null {\n if (!cookieHeader) return null;\n const match = cookieHeader.match(new RegExp(`${name}=([^;]+)`));\n return match?.[1] ?? null;\n}\n\nfunction extractCookieValue(setCookieHeaders: string[], name: string): string | null {\n for (const header of setCookieHeaders) {\n const match = header.match(new RegExp(`^${name}=([^;]+)`));\n if (match?.[1]) return match[1];\n }\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// MastraRBACStudio — role-based permission provider for Studio auth\n// ---------------------------------------------------------------------------\n\nexport interface MastraRBACStudioOptions {\n /**\n * Mapping from role names to permission arrays.\n *\n * @example\n * ```typescript\n * {\n * admin: ['*'],\n * member: ['agents:read', 'workflows:*'],\n * viewer: ['agents:read', 'workflows:read'],\n * _default: [],\n * }\n * ```\n */\n roleMapping: RoleMapping;\n}\n\n/**\n * RBAC provider for Mastra Studio authentication.\n *\n * Maps user roles (from the shared API's /auth/me endpoint) to Mastra permissions\n * using a configurable role mapping.\n */\nexport class MastraRBACStudio implements IRBACProvider<StudioUser> {\n private options: MastraRBACStudioOptions;\n\n get roleMapping(): RoleMapping {\n return this.options.roleMapping;\n }\n\n constructor(options: MastraRBACStudioOptions) {\n this.options = options;\n }\n\n async getRoles(user: StudioUser): Promise<string[]> {\n return user.role ? [user.role] : [];\n }\n\n async hasRole(user: StudioUser, role: string): Promise<boolean> {\n const roles = await this.getRoles(user);\n return roles.includes(role);\n }\n\n async getPermissions(user: StudioUser): Promise<string[]> {\n const roles = await this.getRoles(user);\n if (roles.length === 0) {\n return this.options.roleMapping['_default'] ?? [];\n }\n return resolvePermissionsFromMapping(roles, this.options.roleMapping);\n }\n\n async hasPermission(user: StudioUser, permission: string): Promise<boolean> {\n const permissions = await this.getPermissions(user);\n return permissions.some(p => matchesPermission(p, permission));\n }\n\n async hasAllPermissions(user: StudioUser, permissions: string[]): Promise<boolean> {\n const userPermissions = await this.getPermissions(user);\n return permissions.every(required => userPermissions.some(p => matchesPermission(p, required)));\n }\n\n async hasAnyPermission(user: StudioUser, permissions: string[]): Promise<boolean> {\n const userPermissions = await this.getPermissions(user);\n return permissions.some(required => userPermissions.some(p => matchesPermission(p, required)));\n }\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@mastra/auth-studio",
3
+ "version": "0.0.0-auth-combined-test-all-20260302225441",
4
+ "description": "Mastra Studio Auth integration — proxies authentication through Mastra shared API",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": {
11
+ "types": "./dist/index.d.ts",
12
+ "default": "./dist/index.js"
13
+ },
14
+ "require": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.cjs"
17
+ }
18
+ },
19
+ "./package.json": "./package.json"
20
+ },
21
+ "license": "Apache-2.0",
22
+ "dependencies": {},
23
+ "devDependencies": {
24
+ "@types/node": "22.19.7",
25
+ "@vitest/coverage-v8": "4.0.18",
26
+ "@vitest/ui": "4.0.18",
27
+ "eslint": "^9.37.0",
28
+ "tsup": "^8.5.1",
29
+ "typescript": "^5.9.3",
30
+ "vitest": "4.0.18",
31
+ "@internal/lint": "0.0.0-auth-combined-test-all-20260302225441",
32
+ "@internal/types-builder": "0.0.0-auth-combined-test-all-20260302225441",
33
+ "@mastra/core": "0.0.0-auth-combined-test-all-20260302225441"
34
+ },
35
+ "peerDependencies": {
36
+ "@mastra/core": "0.0.0-auth-combined-test-all-20260302225441"
37
+ },
38
+ "files": [
39
+ "dist",
40
+ "CHANGELOG.md"
41
+ ],
42
+ "homepage": "https://mastra.ai",
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "git+https://github.com/mastra-ai/mastra.git",
46
+ "directory": "auth/studio"
47
+ },
48
+ "bugs": {
49
+ "url": "https://github.com/mastra-ai/mastra/issues"
50
+ },
51
+ "engines": {
52
+ "node": ">=22.13.0"
53
+ },
54
+ "scripts": {
55
+ "build": "tsup --silent --config tsup.config.ts",
56
+ "build:watch": "tsup --watch --silent --config tsup.config.ts",
57
+ "test": "vitest run",
58
+ "lint": "eslint ."
59
+ }
60
+ }