diff --git a/app/client/modules/settings/routes/settings.tsx b/app/client/modules/settings/routes/settings.tsx index 3a304c8b..f348e826 100644 --- a/app/client/modules/settings/routes/settings.tsx +++ b/app/client/modules/settings/routes/settings.tsx @@ -165,7 +165,11 @@ export function SettingsPage({ appContext, initialMembers, initialSsoSettings, i
- + +
+
+ +
diff --git a/app/routes/(dashboard)/settings/index.tsx b/app/routes/(dashboard)/settings/index.tsx index f7816c2e..9034d40b 100644 --- a/app/routes/(dashboard)/settings/index.tsx +++ b/app/routes/(dashboard)/settings/index.tsx @@ -20,7 +20,7 @@ export const Route = createFileRoute("/(dashboard)/settings/")({ }), ]); const orgRole = orgContext.activeMember?.role; - const shouldPrefetchOrgQueries = authContext.user?.role === "admin" || orgRole === "owner" || orgRole === "admin"; + const shouldPrefetchOrgQueries = orgRole === "owner" || orgRole === "admin"; if (shouldPrefetchOrgQueries) { const [org, members, appOrigin] = await Promise.all([ diff --git a/app/server/lib/auth.ts b/app/server/lib/auth.ts index bbcf61f3..0751a479 100644 --- a/app/server/lib/auth.ts +++ b/app/server/lib/auth.ts @@ -2,6 +2,7 @@ import { betterAuth, type AuthContext, type BetterAuthOptions, + type GenericEndpointContext, type MiddlewareContext, type MiddlewareOptions, type User, diff --git a/app/server/lib/auth/helpers/__tests__/create-default-org.test.ts b/app/server/lib/auth/helpers/__tests__/create-default-org.test.ts index 7c649f0d..74d7fa0a 100644 --- a/app/server/lib/auth/helpers/__tests__/create-default-org.test.ts +++ b/app/server/lib/auth/helpers/__tests__/create-default-org.test.ts @@ -1,5 +1,5 @@ import { beforeEach, describe, expect, test } from "bun:test"; -import type { GenericEndpointContext } from "@better-auth/core"; +import type { GenericEndpointContext } from "better-auth"; import { eq } from "drizzle-orm"; import { db } from "~/server/db/db"; import { account, invitation, member, organization, ssoProvider, usersTable } from "~/server/db/schema"; @@ -119,6 +119,45 @@ describe("createUserDefaultOrg", () => { expect(createUserDefaultOrg(userId, ctx)).rejects.toThrow("invite-only"); }); + test("blocks existing users with a personal org from SSO orgs they were not invited to", async () => { + const userId = await createUser("alice@example.com", randomSlug("alice")); + const inviterId = await createUser("inviter@example.com", randomSlug("inviter")); + + const personalOrgId = randomId(); + await db.insert(organization).values({ + id: personalOrgId, + name: "Alice's Workspace", + slug: randomSlug("alice"), + createdAt: new Date(), + }); + await db.insert(member).values({ + id: randomId(), + userId, + organizationId: personalOrgId, + role: "owner", + createdAt: new Date(), + }); + + const ssoOrgId = randomId(); + await db.insert(organization).values({ + id: ssoOrgId, + name: "Acme Corp", + slug: randomSlug("acme"), + createdAt: new Date(), + }); + await db.insert(ssoProvider).values({ + id: randomId(), + providerId: "oidc-acme", + organizationId: ssoOrgId, + userId: inviterId, + issuer: "https://issuer.example.com", + domain: "example.com", + }); + + const ctx = createMockSsoCallbackContext("oidc-acme"); + await expect(createUserDefaultOrg(userId, ctx)).rejects.toThrow("invite-only"); + }); + test("returns existing membership without creating another workspace", async () => { const userId = await createUser("existing-member@example.com", randomSlug("existing-member")); const organizationId = randomId(); diff --git a/app/server/lib/auth/helpers/create-default-org.ts b/app/server/lib/auth/helpers/create-default-org.ts index ca8a1551..aac6e3f2 100644 --- a/app/server/lib/auth/helpers/create-default-org.ts +++ b/app/server/lib/auth/helpers/create-default-org.ts @@ -1,6 +1,6 @@ import { and, eq, gt } from "drizzle-orm"; import { UnauthorizedError } from "http-errors-enhanced"; -import type { GenericEndpointContext } from "@better-auth/core"; +import type { GenericEndpointContext } from "better-auth"; import { db } from "~/server/db/db"; import { invitation, member, organization, ssoProvider, usersTable, type User } from "~/server/db/schema"; import { cryptoUtils } from "~/server/utils/crypto"; @@ -150,17 +150,36 @@ export async function createUserDefaultOrg(userId: string, ctx: GenericEndpointC throw new UnauthorizedError("User not found"); } + const providerId = extractProviderIdFromContext(ctx); + if (providerId) { + const [ssoProviderRecord] = await db + .select() + .from(ssoProvider) + .where(eq(ssoProvider.providerId, providerId)) + .limit(1); + + if (ssoProviderRecord) { + // If the user is already a member of this SSO org (accepted a past invitation), let them through + const existingSsoMembership = await findMembershipWithOrganization(user.id, ssoProviderRecord.organizationId); + if (existingSsoMembership) { + return existingSsoMembership; + } + + // Not yet a member of this SSO org, a valid pending invitation is required. + const invitedMembership = await tryCreateInvitedMembership(userId, normalizeEmail(user.email), ctx); + if (invitedMembership) { + return invitedMembership; + } + } + } + + // Non-SSO path: check for any existing membership before creating a personal org. const existingMembership = await findMembershipWithOrganization(user.id); if (existingMembership) { logger.debug("User already has an organization membership, skipping default org creation", { userId }); return existingMembership; } - const invitedMembership = await tryCreateInvitedMembership(userId, normalizeEmail(user.email), ctx); - if (invitedMembership) { - return invitedMembership; - } - await createDefaultOrganizationMembership(user); const newMembership = await findMembershipWithOrganization(userId); diff --git a/app/server/lib/auth/middlewares/__tests__/require-sso-invitation.test.ts b/app/server/lib/auth/middlewares/__tests__/require-sso-invitation.test.ts index 4c43386f..7346490a 100644 --- a/app/server/lib/auth/middlewares/__tests__/require-sso-invitation.test.ts +++ b/app/server/lib/auth/middlewares/__tests__/require-sso-invitation.test.ts @@ -1,5 +1,5 @@ import { beforeEach, describe, expect, test } from "bun:test"; -import type { GenericEndpointContext } from "@better-auth/core"; +import type { GenericEndpointContext } from "better-auth"; import { db } from "~/server/db/db"; import { account, invitation, member, organization, ssoProvider, usersTable } from "~/server/db/schema"; import { isSsoCallbackRequest, requireSsoInvitation } from "../require-sso-invitation"; diff --git a/app/server/lib/auth/middlewares/__tests__/validate-sso-callback-urls.test.ts b/app/server/lib/auth/middlewares/__tests__/validate-sso-callback-urls.test.ts index c8e3524b..f6f30a3d 100644 --- a/app/server/lib/auth/middlewares/__tests__/validate-sso-callback-urls.test.ts +++ b/app/server/lib/auth/middlewares/__tests__/validate-sso-callback-urls.test.ts @@ -71,4 +71,22 @@ describe("validateSsoCallbackUrls", () => { expect(validateSsoCallbackUrls(ctx)).resolves.toBeUndefined(); }); + + test("rejects URL-encoded external URL (%2F%2Fevil.example)", async () => { + const ctx = createContext("/sign-in/sso", { callbackURL: "%2F%2Fevil.example" }); + + expect(validateSsoCallbackUrls(ctx)).rejects.toThrow("callbackURL"); + }); + + test("rejects URL-encoded reserved path (%2Fsso%2Fcallback%2Ffoo)", async () => { + const ctx = createContext("/sign-in/sso", { callbackURL: "%2Fsso%2Fcallback%2Ffoo" }); + + expect(validateSsoCallbackUrls(ctx)).rejects.toThrow("callbackURL"); + }); + + test("rejects invalid URL encoding (malformed)", async () => { + const ctx = createContext("/sign-in/sso", { callbackURL: "%ZZ" }); + + expect(validateSsoCallbackUrls(ctx)).rejects.toThrow("callbackURL"); + }); }); diff --git a/app/server/lib/auth/middlewares/require-sso-invitation.ts b/app/server/lib/auth/middlewares/require-sso-invitation.ts index fef083f7..7e7ac3bd 100644 --- a/app/server/lib/auth/middlewares/require-sso-invitation.ts +++ b/app/server/lib/auth/middlewares/require-sso-invitation.ts @@ -1,5 +1,5 @@ import { APIError } from "better-auth/api"; -import type { GenericEndpointContext } from "@better-auth/core"; +import type { GenericEndpointContext } from "better-auth"; import { db } from "~/server/db/db"; import { logger } from "~/server/utils/logger"; import { extractProviderIdFromContext, extractProviderIdFromUrl, normalizeEmail } from "../utils/sso-context"; diff --git a/app/server/lib/auth/middlewares/validate-sso-callback-urls.ts b/app/server/lib/auth/middlewares/validate-sso-callback-urls.ts index 48f306f2..2f0d3974 100644 --- a/app/server/lib/auth/middlewares/validate-sso-callback-urls.ts +++ b/app/server/lib/auth/middlewares/validate-sso-callback-urls.ts @@ -2,11 +2,17 @@ import { APIError } from "better-auth/api"; import type { AuthMiddlewareContext } from "~/server/lib/auth"; function isValidCallbackPath(value: string): boolean { - if (!value.startsWith("/") || value.startsWith("//") || value.includes("\\")) { + let decoded: string; + try { + decoded = decodeURIComponent(value); + } catch { + return false; + } + if (!decoded.startsWith("/") || decoded.startsWith("//") || decoded.includes("\\")) { return false; } - if (value.startsWith("/sso/callback/") || value.startsWith("/sso/saml2/")) { + if (decoded.startsWith("/sso/callback/") || decoded.startsWith("/sso/saml2/")) { return false; } diff --git a/app/server/lib/auth/utils/sso-context.ts b/app/server/lib/auth/utils/sso-context.ts index 7c8edac1..1565c8ba 100644 --- a/app/server/lib/auth/utils/sso-context.ts +++ b/app/server/lib/auth/utils/sso-context.ts @@ -1,4 +1,4 @@ -import type { GenericEndpointContext } from "@better-auth/core"; +import type { GenericEndpointContext } from "better-auth"; const SSO_CALLBACK_PATH_SEGMENTS = ["/sso/callback/", "/sso/saml2/callback/", "/sso/saml2/sp/acs/"] as const; diff --git a/app/server/modules/auth/auth.controller.ts b/app/server/modules/auth/auth.controller.ts index 476c66a2..2d5dbef6 100644 --- a/app/server/modules/auth/auth.controller.ts +++ b/app/server/modules/auth/auth.controller.ts @@ -46,20 +46,22 @@ export const authController = new Hono() } const [providersData, invitationsData, autoLinkingSettings] = await Promise.all([ - auth.api.listSSOProviders({ headers }), + auth.api.listSSOProviders({ headers, query: { organizationId: activeOrganizationId } }), auth.api.listInvitations({ headers, query: { organizationId: activeOrganizationId } }), authService.getSsoProviderAutoLinkingSettings(activeOrganizationId), ]); return c.json({ - providers: providersData.providers.map((provider) => ({ - providerId: provider.providerId, - type: provider.type, - issuer: provider.issuer, - domain: provider.domain, - autoLinkMatchingEmails: autoLinkingSettings[provider.providerId] ?? false, - organizationId: provider.organizationId, - })), + providers: providersData.providers + .map((provider) => ({ + providerId: provider.providerId, + type: provider.type, + issuer: provider.issuer, + domain: provider.domain, + autoLinkMatchingEmails: autoLinkingSettings[provider.providerId] ?? false, + organizationId: provider.organizationId, + })) + .filter((p) => p.organizationId === activeOrganizationId), invitations: invitationsData.map((invitation) => ({ id: invitation.id, email: invitation.email, diff --git a/bun.lock b/bun.lock index 9ffb58f0..d26520ed 100644 --- a/bun.lock +++ b/bun.lock @@ -35,7 +35,7 @@ "@tanstack/react-router-ssr-query": "^1.162.9", "@tanstack/react-start": "^1.162.9", "arktype": "^2.1.28", - "better-auth": "1.5.0", + "better-auth": "^1.5.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "commander": "^14.0.2", @@ -218,19 +218,19 @@ "@better-auth/core": ["@better-auth/core@1.5.0", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "zod": "^4.3.6" }, "peerDependencies": { "@better-auth/utils": "0.3.1", "@better-fetch/fetch": "1.1.21", "@cloudflare/workers-types": ">=4", "better-call": "1.3.2", "jose": "^6.1.0", "kysely": "^0.28.5", "nanostores": "^1.0.1" }, "optionalPeers": ["@cloudflare/workers-types"] }, "sha512-nDPmW7I9VGRACEei31fHaZxGwD/yICraDllZ/f25jbWXYaxDaW88RuH1ZhbOUKmGJlZtDxcjN1+YmcVIc1ioNw=="], - "@better-auth/drizzle-adapter": ["@better-auth/drizzle-adapter@1.5.0", "", { "peerDependencies": { "@better-auth/core": "1.5.0", "@better-auth/utils": "^0.3.0", "drizzle-orm": ">=0.41.0" } }, "sha512-qNKAoe+ViiHznipkoOCLo3pDvQo4/6mYbCwnfo2mNbjjopqIn0c3IKW2t+e/Mg4Y18PJcEFeOiIRoY9pUyTtAg=="], + "@better-auth/drizzle-adapter": ["@better-auth/drizzle-adapter@1.5.2", "", { "peerDependencies": { "@better-auth/core": "1.5.2", "@better-auth/utils": "^0.3.0", "drizzle-orm": ">=0.41.0" } }, "sha512-29e7UCwqTriIuDdEr1xbSx4qGg6Ag3aTopzRavPyOCYJyzTwePw8iZ9zaJF1fsLmLeany7LW069NMDf6+3tz/w=="], - "@better-auth/kysely-adapter": ["@better-auth/kysely-adapter@1.5.0", "", { "peerDependencies": { "@better-auth/core": "1.5.0", "@better-auth/utils": "^0.3.0", "kysely": "^0.27.0 || ^0.28.0" } }, "sha512-dSC7yzF58YMrn39srrX/LwMLjd11PtTORjn3RKFwuzVCS07mqMZpPkk3XbQW/ZXxXbdUByrgYQo9z9zFCF37RQ=="], + "@better-auth/kysely-adapter": ["@better-auth/kysely-adapter@1.5.2", "", { "peerDependencies": { "@better-auth/core": "1.5.2", "@better-auth/utils": "^0.3.0", "kysely": "^0.27.0 || ^0.28.0" } }, "sha512-PaP+KPJ6Cw0DxzuZLH6eR0oFhS5Iq/KjYvmZt76fCl5Q7Ys9Cct0kXVVlrD1bftiznTpV+UKMfwjcCWvtc1l4w=="], - "@better-auth/memory-adapter": ["@better-auth/memory-adapter@1.5.0", "", { "peerDependencies": { "@better-auth/core": "1.5.0", "@better-auth/utils": "^0.3.0" } }, "sha512-fp0OtEpWi4RgfxrhhAI8tKW8yHTHx49V12UW1XyuUKrEK0jbu+CzVJSzoMkv/q3fJfjGqDe/vNvWtVBtpIRpQw=="], + "@better-auth/memory-adapter": ["@better-auth/memory-adapter@1.5.2", "", { "peerDependencies": { "@better-auth/core": "1.5.2", "@better-auth/utils": "^0.3.0" } }, "sha512-vCbmMpUAisISRVxzNFIxkvO3wm63fzwSxAOO9Xktl77VyEyh8zliBNcW8S6+9DOeolVRKhjWEg7UaBOtIhFX/Q=="], - "@better-auth/mongo-adapter": ["@better-auth/mongo-adapter@1.5.0", "", { "peerDependencies": { "@better-auth/core": "1.5.0", "@better-auth/utils": "^0.3.0", "mongodb": "^6.0.0 || ^7.0.0" } }, "sha512-qI+MiewH6kzUbNkKBX4fdhPl1MkIXq8V7v3TEt/DLAHC4/QxmPqhxQHEDeZBxO+NH8+Zekr2sQzKRRFfbaQKbw=="], + "@better-auth/mongo-adapter": ["@better-auth/mongo-adapter@1.5.2", "", { "peerDependencies": { "@better-auth/core": "1.5.2", "@better-auth/utils": "^0.3.0", "mongodb": "^6.0.0 || ^7.0.0" } }, "sha512-fJd+Z7fgRFgK2W7oxbFYM9K10yEUs/hlALzihCdDgSyRg9XFLBMJkMcECRqBsop/cZUjwZxLBTQPsIpgx9ix1g=="], - "@better-auth/prisma-adapter": ["@better-auth/prisma-adapter@1.5.0", "", { "dependencies": { "@prisma/client": "^7.4.1" }, "peerDependencies": { "@better-auth/core": "1.5.0", "@better-auth/utils": "^0.3.0", "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-Sga8DTeCCsamGZ7/54kH0HKlrCrgW4EApadAgsufsIcRqHteeKC5rNCLIppfyRa/xJxm5xImUeks6Nvz3zL1tw=="], + "@better-auth/prisma-adapter": ["@better-auth/prisma-adapter@1.5.2", "", { "dependencies": { "@prisma/client": "^7.4.1" }, "peerDependencies": { "@better-auth/core": "1.5.2", "@better-auth/utils": "^0.3.0", "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-9GB4q91Q16wSSsi1vFP/RZNW0GNmdxTiDcE2MX1fC4Hlmo6UuT4WRv+94YPYs3/tPhsJ17k5Lt+rKTOK8S6Kbw=="], "@better-auth/sso": ["@better-auth/sso@1.5.0", "", { "dependencies": { "@better-auth/utils": "0.3.1", "@better-fetch/fetch": "1.1.21", "fast-xml-parser": "^5.4.1", "jose": "^6.1.3", "samlify": "^2.10.2", "zod": "^4.3.6" }, "peerDependencies": { "@better-auth/core": "1.5.0", "better-auth": "1.5.0", "better-call": "1.3.2" } }, "sha512-HuomPV25de9y2A/8WX4UtDHdHj4OUlwbnTH/NAuhmqUGyj7VZrOBwUaZhmD6roVhF18+YigOmGPetajukMZrQQ=="], - "@better-auth/telemetry": ["@better-auth/telemetry@1.5.0", "", { "dependencies": { "@better-auth/utils": "0.3.1", "@better-fetch/fetch": "1.1.21" }, "peerDependencies": { "@better-auth/core": "1.5.0" } }, "sha512-/6ThGSnGPVTR4A/6F8kv65UomDHtM24y2yRZuJfWYbqkve0jn8+WVsxOfQN9bx7J16zIvYw5hJAYCwxoj20BTQ=="], + "@better-auth/telemetry": ["@better-auth/telemetry@1.5.2", "", { "dependencies": { "@better-auth/utils": "0.3.1", "@better-fetch/fetch": "1.1.21" }, "peerDependencies": { "@better-auth/core": "1.5.2" } }, "sha512-Cukyj5yciFNGtx5SkQCop2wOjpHuq2ZHL3V7ydVFe51WUNCXd+v1Sbed2sIfT/8hOcSB+NefALXNv1yTSxKkAQ=="], "@better-auth/utils": ["@better-auth/utils@0.3.1", "", {}, "sha512-+CGp4UmZSUrHHnpHhLPYu6cV+wSUSvVbZbNykxhUDocpVNTo9uFFxw/NqJlh1iC4wQ9HKKWGCKuZ5wUgS0v6Kg=="], @@ -1000,7 +1000,7 @@ "baseline-browser-mapping": ["baseline-browser-mapping@2.10.0", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA=="], - "better-auth": ["better-auth@1.5.0", "", { "dependencies": { "@better-auth/core": "1.5.0", "@better-auth/drizzle-adapter": "1.5.0", "@better-auth/kysely-adapter": "1.5.0", "@better-auth/memory-adapter": "1.5.0", "@better-auth/mongo-adapter": "1.5.0", "@better-auth/prisma-adapter": "1.5.0", "@better-auth/telemetry": "1.5.0", "@better-auth/utils": "0.3.1", "@better-fetch/fetch": "1.1.21", "@noble/ciphers": "^2.1.1", "@noble/hashes": "^2.0.1", "better-call": "1.3.2", "defu": "^6.1.4", "jose": "^6.1.3", "kysely": "^0.28.11", "nanostores": "^1.1.1", "zod": "^4.3.6" }, "peerDependencies": { "@lynx-js/react": "*", "@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0", "@sveltejs/kit": "^2.0.0", "@tanstack/react-start": "^1.0.0", "@tanstack/solid-start": "^1.0.0", "better-sqlite3": "^12.0.0", "drizzle-kit": ">=0.31.4", "drizzle-orm": ">=0.41.0", "mongodb": "^6.0.0 || ^7.0.0", "mysql2": "^3.0.0", "next": "^14.0.0 || ^15.0.0 || ^16.0.0", "pg": "^8.0.0", "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0", "solid-js": "^1.0.0", "svelte": "^4.0.0 || ^5.0.0", "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0", "vue": "^3.0.0" }, "optionalPeers": ["@lynx-js/react", "@prisma/client", "@sveltejs/kit", "@tanstack/react-start", "@tanstack/solid-start", "better-sqlite3", "drizzle-kit", "drizzle-orm", "mongodb", "mysql2", "next", "pg", "prisma", "react", "react-dom", "solid-js", "svelte", "vitest", "vue"] }, "sha512-vbRKSxDa1vwXzEmR7+kXJMDs2pRXLOvD4MiqQwL4r6kkjzok5kOyLD200ZUg24Jtx2Xho1oA2drlxT6GqknH1A=="], + "better-auth": ["better-auth@1.5.2", "", { "dependencies": { "@better-auth/core": "1.5.2", "@better-auth/drizzle-adapter": "1.5.2", "@better-auth/kysely-adapter": "1.5.2", "@better-auth/memory-adapter": "1.5.2", "@better-auth/mongo-adapter": "1.5.2", "@better-auth/prisma-adapter": "1.5.2", "@better-auth/telemetry": "1.5.2", "@better-auth/utils": "0.3.1", "@better-fetch/fetch": "1.1.21", "@noble/ciphers": "^2.1.1", "@noble/hashes": "^2.0.1", "better-call": "1.3.2", "defu": "^6.1.4", "jose": "^6.1.3", "kysely": "^0.28.11", "nanostores": "^1.1.1", "zod": "^4.3.6" }, "peerDependencies": { "@lynx-js/react": "*", "@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0", "@sveltejs/kit": "^2.0.0", "@tanstack/react-start": "^1.0.0", "@tanstack/solid-start": "^1.0.0", "better-sqlite3": "^12.0.0", "drizzle-kit": ">=0.31.4", "drizzle-orm": ">=0.41.0", "mongodb": "^6.0.0 || ^7.0.0", "mysql2": "^3.0.0", "next": "^14.0.0 || ^15.0.0 || ^16.0.0", "pg": "^8.0.0", "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0", "solid-js": "^1.0.0", "svelte": "^4.0.0 || ^5.0.0", "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0", "vue": "^3.0.0" }, "optionalPeers": ["@lynx-js/react", "@prisma/client", "@sveltejs/kit", "@tanstack/react-start", "@tanstack/solid-start", "better-sqlite3", "drizzle-kit", "drizzle-orm", "mongodb", "mysql2", "next", "pg", "prisma", "react", "react-dom", "solid-js", "svelte", "vitest", "vue"] }, "sha512-xEnt/RBsu/cjcN+IEsgeBqka/6QRaGzPFl5hnnJfZU/JxRGnDsVUDHXvJQRfecj8qA/1nPJOQjZ6qQL1Z7aN+Q=="], "better-call": ["better-call@1.3.2", "", { "dependencies": { "@better-auth/utils": "^0.3.1", "@better-fetch/fetch": "^1.1.21", "rou3": "^0.7.12", "set-cookie-parser": "^3.0.1" }, "peerDependencies": { "zod": "^4.0.0" }, "optionalPeers": ["zod"] }, "sha512-4cZIfrerDsNTn3cm+MhLbUePN0gdwkhSXEuG7r/zuQ8c/H7iU0/jSK5TD3FW7U0MgKHce/8jGpPYNO4Ve+4NBw=="], @@ -1788,7 +1788,7 @@ "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], - "tr46": ["tr46@5.1.1", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw=="], + "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], "trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="], @@ -1864,7 +1864,7 @@ "web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="], - "webidl-conversions": ["webidl-conversions@7.0.0", "", {}, "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="], + "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], "webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="], @@ -1872,7 +1872,7 @@ "whatwg-mimetype": ["whatwg-mimetype@3.0.0", "", {}, "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q=="], - "whatwg-url": ["whatwg-url@14.2.0", "", { "dependencies": { "tr46": "^5.1.0", "webidl-conversions": "^7.0.0" } }, "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw=="], + "whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], @@ -1908,6 +1908,18 @@ "@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "@better-auth/drizzle-adapter/@better-auth/core": ["@better-auth/core@1.5.2", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "zod": "^4.3.6" }, "peerDependencies": { "@better-auth/utils": "0.3.1", "@better-fetch/fetch": "1.1.21", "@cloudflare/workers-types": ">=4", "better-call": "1.3.2", "jose": "^6.1.0", "kysely": "^0.28.5", "nanostores": "^1.0.1" }, "optionalPeers": ["@cloudflare/workers-types"] }, "sha512-svaKRVN/p3+g++kljLEedHC+RgDlGsVr87tKiATr5xIE7xqLO1If906pMTNMfhF08N5r7pMbix/mRYdObuPKHA=="], + + "@better-auth/kysely-adapter/@better-auth/core": ["@better-auth/core@1.5.2", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "zod": "^4.3.6" }, "peerDependencies": { "@better-auth/utils": "0.3.1", "@better-fetch/fetch": "1.1.21", "@cloudflare/workers-types": ">=4", "better-call": "1.3.2", "jose": "^6.1.0", "kysely": "^0.28.5", "nanostores": "^1.0.1" }, "optionalPeers": ["@cloudflare/workers-types"] }, "sha512-svaKRVN/p3+g++kljLEedHC+RgDlGsVr87tKiATr5xIE7xqLO1If906pMTNMfhF08N5r7pMbix/mRYdObuPKHA=="], + + "@better-auth/memory-adapter/@better-auth/core": ["@better-auth/core@1.5.2", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "zod": "^4.3.6" }, "peerDependencies": { "@better-auth/utils": "0.3.1", "@better-fetch/fetch": "1.1.21", "@cloudflare/workers-types": ">=4", "better-call": "1.3.2", "jose": "^6.1.0", "kysely": "^0.28.5", "nanostores": "^1.0.1" }, "optionalPeers": ["@cloudflare/workers-types"] }, "sha512-svaKRVN/p3+g++kljLEedHC+RgDlGsVr87tKiATr5xIE7xqLO1If906pMTNMfhF08N5r7pMbix/mRYdObuPKHA=="], + + "@better-auth/mongo-adapter/@better-auth/core": ["@better-auth/core@1.5.2", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "zod": "^4.3.6" }, "peerDependencies": { "@better-auth/utils": "0.3.1", "@better-fetch/fetch": "1.1.21", "@cloudflare/workers-types": ">=4", "better-call": "1.3.2", "jose": "^6.1.0", "kysely": "^0.28.5", "nanostores": "^1.0.1" }, "optionalPeers": ["@cloudflare/workers-types"] }, "sha512-svaKRVN/p3+g++kljLEedHC+RgDlGsVr87tKiATr5xIE7xqLO1If906pMTNMfhF08N5r7pMbix/mRYdObuPKHA=="], + + "@better-auth/prisma-adapter/@better-auth/core": ["@better-auth/core@1.5.2", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "zod": "^4.3.6" }, "peerDependencies": { "@better-auth/utils": "0.3.1", "@better-fetch/fetch": "1.1.21", "@cloudflare/workers-types": ">=4", "better-call": "1.3.2", "jose": "^6.1.0", "kysely": "^0.28.5", "nanostores": "^1.0.1" }, "optionalPeers": ["@cloudflare/workers-types"] }, "sha512-svaKRVN/p3+g++kljLEedHC+RgDlGsVr87tKiATr5xIE7xqLO1If906pMTNMfhF08N5r7pMbix/mRYdObuPKHA=="], + + "@better-auth/telemetry/@better-auth/core": ["@better-auth/core@1.5.2", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "zod": "^4.3.6" }, "peerDependencies": { "@better-auth/utils": "0.3.1", "@better-fetch/fetch": "1.1.21", "@cloudflare/workers-types": ">=4", "better-call": "1.3.2", "jose": "^6.1.0", "kysely": "^0.28.5", "nanostores": "^1.0.1" }, "optionalPeers": ["@cloudflare/workers-types"] }, "sha512-svaKRVN/p3+g++kljLEedHC+RgDlGsVr87tKiATr5xIE7xqLO1If906pMTNMfhF08N5r7pMbix/mRYdObuPKHA=="], + "@hey-api/shared/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], "@prisma/config/c12": ["c12@3.1.0", "", { "dependencies": { "chokidar": "^4.0.3", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^16.6.1", "exsolve": "^1.0.7", "giget": "^2.0.0", "jiti": "^2.4.2", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^1.0.0", "pkg-types": "^2.2.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "^0.3.5" }, "optionalPeers": ["magicast"] }, "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw=="], @@ -1974,6 +1986,8 @@ "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "better-auth/@better-auth/core": ["@better-auth/core@1.5.2", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "zod": "^4.3.6" }, "peerDependencies": { "@better-auth/utils": "0.3.1", "@better-fetch/fetch": "1.1.21", "@cloudflare/workers-types": ">=4", "better-call": "1.3.2", "jose": "^6.1.0", "kysely": "^0.28.5", "nanostores": "^1.0.1" }, "optionalPeers": ["@cloudflare/workers-types"] }, "sha512-svaKRVN/p3+g++kljLEedHC+RgDlGsVr87tKiATr5xIE7xqLO1If906pMTNMfhF08N5r7pMbix/mRYdObuPKHA=="], + "cheerio/whatwg-mimetype": ["whatwg-mimetype@4.0.0", "", {}, "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg=="], "cross-fetch/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], @@ -1990,6 +2004,8 @@ "libsql/detect-libc": ["detect-libc@2.0.2", "", {}, "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw=="], + "mongodb-connection-string-url/whatwg-url": ["whatwg-url@14.2.0", "", { "dependencies": { "tr46": "^5.1.0", "webidl-conversions": "^7.0.0" } }, "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw=="], + "mssql/commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], "mssql/tedious": ["tedious@18.6.2", "", { "dependencies": { "@azure/core-auth": "^1.7.2", "@azure/identity": "^4.2.1", "@azure/keyvault-keys": "^4.4.0", "@js-joda/core": "^5.6.1", "@types/node": ">=18", "bl": "^6.0.11", "iconv-lite": "^0.6.3", "js-md4": "^0.3.2", "native-duplexpair": "^1.0.0", "sprintf-js": "^1.1.3" } }, "sha512-g7jC56o3MzLkE3lHkaFe2ZdOVFBahq5bsB60/M4NYUbocw/MCrS89IOEQUFr+ba6pb8ZHczZ/VqCyYeYq0xBAg=="], @@ -2020,16 +2036,14 @@ "@tanstack/router-plugin/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], - "cross-fetch/node-fetch/whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], + "mongodb-connection-string-url/whatwg-url/tr46": ["tr46@5.1.1", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw=="], + + "mongodb-connection-string-url/whatwg-url/webidl-conversions": ["webidl-conversions@7.0.0", "", {}, "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="], "mssql/tedious/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], "@prisma/config/c12/chokidar/readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], "@tanstack/router-plugin/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - - "cross-fetch/node-fetch/whatwg-url/tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], - - "cross-fetch/node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], } } diff --git a/package.json b/package.json index 3f001fcd..c4eb4a25 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "@tanstack/react-router-ssr-query": "^1.162.9", "@tanstack/react-start": "^1.162.9", "arktype": "^2.1.28", - "better-auth": "1.5.0", + "better-auth": "^1.5.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "commander": "^14.0.2",