Skip to content

Commit 25cbf5c

Browse files
authored
Merge pull request #900 from objectstack-ai/copilot/refactor-auth-plugin-better-auth
2 parents 94fa20b + 6feba7f commit 25cbf5c

3 files changed

Lines changed: 53 additions & 23 deletions

File tree

packages/plugins/plugin-auth/src/auth-manager.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,45 @@ describe('AuthManager', () => {
259259
});
260260
});
261261

262+
describe('basePath configuration', () => {
263+
it('should default basePath to /api/v1/auth when not specified', () => {
264+
let capturedConfig: any;
265+
(betterAuth as any).mockImplementation((config: any) => {
266+
capturedConfig = config;
267+
return { handler: vi.fn(), api: {} };
268+
});
269+
270+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
271+
const manager = new AuthManager({
272+
secret: 'test-secret-at-least-32-chars-long',
273+
baseUrl: 'http://localhost:3000',
274+
});
275+
manager.getAuthInstance();
276+
warnSpy.mockRestore();
277+
278+
expect(capturedConfig.basePath).toBe('/api/v1/auth');
279+
});
280+
281+
it('should use custom basePath when provided', () => {
282+
let capturedConfig: any;
283+
(betterAuth as any).mockImplementation((config: any) => {
284+
capturedConfig = config;
285+
return { handler: vi.fn(), api: {} };
286+
});
287+
288+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
289+
const manager = new AuthManager({
290+
secret: 'test-secret-at-least-32-chars-long',
291+
baseUrl: 'http://localhost:3000',
292+
basePath: '/custom/auth',
293+
});
294+
manager.getAuthInstance();
295+
warnSpy.mockRestore();
296+
297+
expect(capturedConfig.basePath).toBe('/custom/auth');
298+
});
299+
});
300+
262301
describe('plugin registration', () => {
263302
it('should not include any plugins when no plugin config is provided', () => {
264303
let capturedConfig: any;

packages/plugins/plugin-auth/src/auth-manager.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ export interface AuthManagerOptions extends Partial<AuthConfig> {
3232
* Required for database operations using ObjectQL instead of third-party ORMs
3333
*/
3434
dataEngine?: IDataEngine;
35+
36+
/**
37+
* Base path for auth routes
38+
* Forwarded to better-auth's basePath option so it can match incoming
39+
* request URLs without manual path rewriting.
40+
* @default '/api/v1/auth'
41+
*/
42+
basePath?: string;
3543
}
3644

3745
/**
@@ -79,7 +87,7 @@ export class AuthManager {
7987
// Base configuration
8088
secret: this.config.secret || this.generateSecret(),
8189
baseURL: this.config.baseUrl || 'http://localhost:3000',
82-
basePath: '/', // ← 关键修复!告诉 better-auth 路径已被剥离
90+
basePath: this.config.basePath || '/api/v1/auth',
8391

8492
// Database adapter configuration
8593
database: this.createDatabaseConfig(),

packages/plugins/plugin-auth/src/auth-plugin.ts

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -181,30 +181,13 @@ export class AuthPlugin implements Plugin {
181181

182182
const rawApp = (httpServer as any).getRawApp();
183183

184-
// Register wildcard route to forward all auth requests to better-auth
185-
// Better-auth expects requests at its baseURL, so we need to preserve the full path
184+
// Register wildcard route to forward all auth requests to better-auth.
185+
// better-auth is configured with basePath matching our route prefix, so we
186+
// forward the original request directly — no path rewriting needed.
186187
rawApp.all(`${basePath}/*`, async (c: any) => {
187188
try {
188-
// Get the Web standard Request from Hono context
189-
const request = c.req.raw as Request;
190-
191-
// Create a new Request with the path rewritten to match better-auth's expectations
192-
// Better-auth expects paths like /sign-in/email, /sign-up/email, etc.
193-
// We need to strip our basePath prefix
194-
const url = new URL(request.url);
195-
const authPath = url.pathname.replace(basePath, '');
196-
const rewrittenUrl = new URL(authPath || '/', url.origin);
197-
rewrittenUrl.search = url.search; // Preserve query params
198-
199-
const rewrittenRequest = new Request(rewrittenUrl, {
200-
method: request.method,
201-
headers: request.headers,
202-
body: request.body,
203-
duplex: 'half' as any, // Required for Request with body
204-
});
205-
206-
// Forward to better-auth handler
207-
const response = await this.authManager!.handleRequest(rewrittenRequest);
189+
// Forward the original request to better-auth handler
190+
const response = await this.authManager!.handleRequest(c.req.raw);
208191

209192
// better-auth catches internal errors and returns error Responses
210193
// without throwing, so the catch block below would never trigger.

0 commit comments

Comments
 (0)