diff --git a/packages/better-auth/src/api/middlewares/origin-check.test.ts b/packages/better-auth/src/api/middlewares/origin-check.test.ts index ba5a750743..2fd60ce1d0 100644 --- a/packages/better-auth/src/api/middlewares/origin-check.test.ts +++ b/packages/better-auth/src/api/middlewares/origin-check.test.ts @@ -73,6 +73,24 @@ describe("Origin Check", async (it) => { expect(res.data?.user).toBeDefined(); }); + it("should allow plus signs in the callback url", async (ctx) => { + const client = createAuthClient({ + baseURL: "http://localhost:3000", + fetchOptions: { + customFetchImpl, + headers: { + origin: "https://localhost:3000", + }, + }, + }); + const res = await client.signIn.email({ + email: testUser.email, + password: testUser.password, + callbackURL: "/dashboard+page?test=123+456", + }); + expect(res.data?.user).toBeDefined(); + }); + it("should reject callback url with double slash", async (ctx) => { const client = createAuthClient({ baseURL: "http://localhost:3000", diff --git a/packages/better-auth/src/api/middlewares/origin-check.ts b/packages/better-auth/src/api/middlewares/origin-check.ts index 24ced986d7..e34d2561fd 100644 --- a/packages/better-auth/src/api/middlewares/origin-check.ts +++ b/packages/better-auth/src/api/middlewares/origin-check.ts @@ -49,7 +49,7 @@ export const originCheckMiddleware = createAuthMiddleware(async (ctx) => { matchesPattern(url, origin) || (url?.startsWith("/") && label !== "origin" && - /^\/(?!\/|\\|%2f|%5c)[\w\-./]*(?:\?[\w\-./=&%]*)?$/.test(url)), + /^\/(?!\/|\\|%2f|%5c)[\w\-.\+/]*(?:\?[\w\-.\+/=&%]*)?$/.test(url)), ); if (!isTrustedOrigin) { ctx.context.logger.error(`Invalid ${label}: ${url}`); @@ -106,7 +106,7 @@ export const originCheck = ( matchesPattern(url, origin) || (url?.startsWith("/") && label !== "origin" && - /^\/(?!\/|\\|%2f|%5c)[\w\-./]*(?:\?[\w\-./=&%]*)?$/.test(url)), + /^\/(?!\/|\\|%2f|%5c)[\w\-.\+/]*(?:\?[\w\-.\+/=&%]*)?$/.test(url)), ); if (!isTrustedOrigin) { ctx.context.logger.error(`Invalid ${label}: ${url}`);