mirror of
https://github.com/LukeHagar/better-auth.git
synced 2025-12-07 20:37:44 +00:00
feat: cross-subdomainCookies plugin
This commit is contained in:
@@ -1,5 +1,10 @@
|
||||
import { betterAuth } from "better-auth";
|
||||
import { organization, passkey, twoFactor } from "better-auth/plugins";
|
||||
import {
|
||||
organization,
|
||||
passkey,
|
||||
twoFactor,
|
||||
crossSubdomain,
|
||||
} from "better-auth/plugins";
|
||||
import { reactInvitationEmail } from "./email/invitation";
|
||||
import { LibsqlDialect } from "@libsql/kysely-libsql";
|
||||
import { github, google } from "better-auth/social-providers";
|
||||
@@ -75,6 +80,7 @@ export const auth = betterAuth({
|
||||
},
|
||||
}),
|
||||
passkey(),
|
||||
crossSubdomain(),
|
||||
],
|
||||
socialProviders: {
|
||||
github: {
|
||||
|
||||
@@ -174,6 +174,17 @@ export const router = <C extends AuthContext, Option extends BetterAuthOptions>(
|
||||
async onRequest(req) {
|
||||
return onRequestRateLimit(req, ctx);
|
||||
},
|
||||
async onResponse(res) {
|
||||
for (const plugin of ctx.options.plugins || []) {
|
||||
if (plugin.onResponse) {
|
||||
const response = await plugin.onResponse(res, ctx);
|
||||
if (response) {
|
||||
return response.response;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
},
|
||||
onError(e) {
|
||||
const log = options.logger?.verboseLogging ? logger : undefined;
|
||||
if (options.logger?.disabled !== true) {
|
||||
|
||||
78
packages/better-auth/src/plugins/cross-subdomain/index.ts
Normal file
78
packages/better-auth/src/plugins/cross-subdomain/index.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { createAuthMiddleware } from "../../api";
|
||||
import type { BetterAuthPlugin } from "../../types";
|
||||
|
||||
interface Options {
|
||||
/**
|
||||
* By default, domain name will be extracted from base URL
|
||||
* you can provide a custom domain name here
|
||||
*/
|
||||
domainName?: string;
|
||||
/**
|
||||
* List of cookies that should be shared across subdomains
|
||||
*
|
||||
* by default, only sessionToken, csrfToken and dontRememberToken
|
||||
* cookies will be shared across subdomains
|
||||
*/
|
||||
eligibleCookies?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* This plugin will update the domain of the cookies
|
||||
* that are eligible to be shared across subdomains
|
||||
* @param options
|
||||
* @category Plugins
|
||||
*/
|
||||
export const crossSubdomainCookies = (options?: Options) => {
|
||||
return {
|
||||
id: "cross-subdomain-cookies",
|
||||
async onResponse(response, ctx) {
|
||||
const setCookie = response.headers.get("set-cookie");
|
||||
if (!setCookie) return;
|
||||
const baseURL = ctx.baseURL;
|
||||
const cookieParts = setCookie.split(";");
|
||||
const domain = options?.domainName || new URL(baseURL).hostname;
|
||||
const authCookies = ctx.authCookies;
|
||||
const cookieNamesEligibleForDomain = [
|
||||
authCookies.sessionToken.name,
|
||||
authCookies.csrfToken.name,
|
||||
authCookies.dontRememberToken.name,
|
||||
];
|
||||
|
||||
if (
|
||||
!cookieNamesEligibleForDomain.some((name) => setCookie.includes(name))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedCookies = cookieParts
|
||||
.map((part) => {
|
||||
if (
|
||||
!cookieNamesEligibleForDomain.some((name) =>
|
||||
part.toLowerCase().includes(name.toLowerCase()),
|
||||
)
|
||||
) {
|
||||
return part;
|
||||
}
|
||||
|
||||
const trimmedPart = part.trim();
|
||||
if (trimmedPart.toLowerCase().startsWith("domain=")) {
|
||||
return `Domain=${domain}`;
|
||||
}
|
||||
if (!trimmedPart.toLowerCase().includes("domain=")) {
|
||||
return `${trimmedPart}; Domain=${domain}`;
|
||||
}
|
||||
return trimmedPart;
|
||||
})
|
||||
.filter(
|
||||
(part, index, self) =>
|
||||
index ===
|
||||
self.findIndex((p) => p.split(";")[0] === part.split(";")[0]),
|
||||
)
|
||||
.join("; ");
|
||||
response.headers.set("set-cookie", updatedCookies);
|
||||
return {
|
||||
response,
|
||||
};
|
||||
},
|
||||
} satisfies BetterAuthPlugin;
|
||||
};
|
||||
@@ -7,3 +7,4 @@ export * from "../types/plugins";
|
||||
export * from "../api/call";
|
||||
export * from "../utils/hide-metadata";
|
||||
export * from "./magic-link";
|
||||
export * from "./cross-subdomain";
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import type { ContextTools } from "better-call";
|
||||
import type { AuthContext } from "../init";
|
||||
|
||||
export type HookEndpointContext = ContextTools & {
|
||||
context: AuthContext;
|
||||
} & {
|
||||
body: any;
|
||||
request?: Request;
|
||||
headers?: Headers;
|
||||
params?: Record<string, string> | undefined;
|
||||
query?: any;
|
||||
method?: any;
|
||||
};
|
||||
export type HookEndpointContext<C extends Record<string, any> = {}> =
|
||||
ContextTools & {
|
||||
context: AuthContext & C;
|
||||
} & {
|
||||
body: any;
|
||||
request?: Request;
|
||||
headers?: Headers;
|
||||
params?: Record<string, string> | undefined;
|
||||
query?: any;
|
||||
method?: any;
|
||||
};
|
||||
|
||||
export type GenericEndpointContext = ContextTools & {
|
||||
context: AuthContext;
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { AuthEndpoint } from "../api/call";
|
||||
import type { FieldAttribute } from "../db/field";
|
||||
import type { HookEndpointContext } from "./context";
|
||||
import type { LiteralString } from "./helper";
|
||||
import type { AuthContext } from ".";
|
||||
|
||||
export type PluginSchema = {
|
||||
[table: string]: {
|
||||
@@ -23,6 +24,12 @@ export type BetterAuthPlugin = {
|
||||
path: string;
|
||||
middleware: Endpoint;
|
||||
}[];
|
||||
onResponse?: (
|
||||
response: Response,
|
||||
ctx: AuthContext,
|
||||
) => Promise<{
|
||||
response: Response;
|
||||
} | void>;
|
||||
hooks?: {
|
||||
before?: {
|
||||
matcher: (context: HookEndpointContext) => boolean;
|
||||
@@ -33,9 +40,9 @@ export type BetterAuthPlugin = {
|
||||
after?: {
|
||||
matcher: (context: HookEndpointContext) => boolean;
|
||||
handler: (
|
||||
context: HookEndpointContext & {
|
||||
context: HookEndpointContext<{
|
||||
returned: EndpointResponse;
|
||||
},
|
||||
}>,
|
||||
) => Promise<void | {
|
||||
response: EndpointResponse;
|
||||
}>;
|
||||
|
||||
Reference in New Issue
Block a user