[GH-ISSUE #2180] How can I handle redirect in a monorepo Next.js with clean frontend/backend separation? #26410

Closed
opened 2026-04-17 16:58:03 -05:00 by GiteaMirror · 8 comments
Owner

Originally created by @rinarakaki on GitHub (Apr 8, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/2180

My code structure is like this:

  • apps
    • backend
      • primsa
        • schema.prisma
      • src
        • auth.ts
      • package.json
    • frontend
      • app
        • api/auth/[...all]/route.ts
        • auth-client.ts
      • package.json

I want to keep my code as clean as possible and don't want to expose any Prisma-related code to the frontend.
The problem is that to handle redirects, I need to define a route handler in api/auth/[...all]/route.ts in the frontend project. And to do that, I need to reference auth.ts instead of auth-client.ts, which is across the frontend/backend project boundary, otherwise I have to include all the Prisma-related dependencies and code in the frontend. How can I solve this?

Originally created by @rinarakaki on GitHub (Apr 8, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/2180 My code structure is like this: - apps - backend - primsa - schema.prisma - src - auth.ts - package.json - frontend - app - api/auth/[...all]/route.ts - auth-client.ts - package.json I want to keep my code as clean as possible and don't want to expose any Prisma-related code to the frontend. The problem is that to handle redirects, I need to define a route handler in `api/auth/[...all]/route.ts` in the frontend project. And to do that, I need to reference `auth.ts` instead of `auth-client.ts`, which is across the frontend/backend project boundary, otherwise I have to include all the Prisma-related dependencies and code in the frontend. How can I solve this?
GiteaMirror added the locked label 2026-04-17 16:58:03 -05:00
Author
Owner

@Kinfe123 commented on GitHub (Apr 9, 2025):

why not you define the route handling with the backend workspace since it is also backend work as well ?

<!-- gh-comment-id:2788291071 --> @Kinfe123 commented on GitHub (Apr 9, 2025): why not you define the route handling with the backend workspace since it is also backend work as well ?
Author
Owner

@rinarakaki commented on GitHub (Apr 9, 2025):

Yeah, I agree that's the best way. Could you please tell me how the flow after it gets redirected to the backend api endpoint look like, and point to some material how to implement it if possible?

<!-- gh-comment-id:2788391818 --> @rinarakaki commented on GitHub (Apr 9, 2025): Yeah, I agree that's the best way. Could you please tell me how the flow after it gets redirected to the backend api endpoint look like, and point to some material how to implement it if possible?
Author
Owner

@Kinfe123 commented on GitHub (Apr 9, 2025):

In your monorepo setup, the frontend project makes requests to your backend project's auth endpoints, where Better Auth's handler processes these requests through its middleware chain, managing sessions, cookies, and authentication logic, while your backend project simply needs to mount these endpoints and handle the responses.
The key is to create a shared auth configs package in your monorepo that both projects can import, with the backend project exposing the auth endpoints and the frontend project making requests to these endpoints, ensuring consistent auth behavior across your entire application while maintaining proper separation of concerns.

<!-- gh-comment-id:2788611084 --> @Kinfe123 commented on GitHub (Apr 9, 2025): In your monorepo setup, the frontend project makes requests to your backend project's auth endpoints, where Better Auth's handler processes these requests through its middleware chain, managing sessions, cookies, and authentication logic, while your backend project simply needs to mount these endpoints and handle the responses. The key is to create a shared auth configs package in your monorepo that both projects can import, with the backend project exposing the auth endpoints and the frontend project making requests to these endpoints, ensuring consistent auth behavior across your entire application while maintaining proper separation of concerns.
Author
Owner

@rinarakaki commented on GitHub (Apr 10, 2025):

But I don't want to complicate the repository structure like...:

  • apps
    • backend
      • package.json
    • frontend
      • app
        • auth-client.ts
      • package.json
  • packages
    • auth
      • src
        • auth.ts
      • package.json
    • prisma
      • package.json

Isn't this what you suggest?

By the way, can't we properly handle redirects without referencing auth.ts?

<!-- gh-comment-id:2794668823 --> @rinarakaki commented on GitHub (Apr 10, 2025): But I don't want to complicate the repository structure like...: - apps - backend - package.json - frontend - app - auth-client.ts - package.json - packages - auth - src - auth.ts - package.json - prisma - package.json Isn't this what you suggest? By the way, can't we properly handle redirects without referencing auth.ts?
Author
Owner

@Kinfe123 commented on GitHub (Apr 11, 2025):

You can directly hit the endpoints on the backend and do refer the auth there and if you got a session data , handle the redirection from there on the frontend as well

<!-- gh-comment-id:2796424709 --> @Kinfe123 commented on GitHub (Apr 11, 2025): You can directly hit the endpoints on the backend and do refer the auth there and if you got a session data , handle the redirection from there on the frontend as well
Author
Owner

@rinarakaki commented on GitHub (Apr 13, 2025):

That's beautiful. I'm trying that solution. Could you please tell me how I can implement this?

if you got a session data , handle the redirection from there on the frontend as well

Here are the context:

auth.ts

export const auth = betterAuth({
  ..., 
  socialProviders: {
    google: {
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
      redirectURI: "http://localhost:8080/api/auth/callback/google",
    },
  },
});

server.ts

app.all("/api/auth/*splat", toNodeHandler(auth));

and I got:

::1 - - [13/Apr/2025:08:29:23 +0000] "GET /api/auth/callback/google?... HTTP/1.1" 302 - "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36"
::1 - - [13/Apr/2025:08:29:23 +0000] "GET / HTTP/1.1" 404 139 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36"

It automatically redirects to the backend's root URL. How can I control the process after the callback is called?

<!-- gh-comment-id:2799863638 --> @rinarakaki commented on GitHub (Apr 13, 2025): That's beautiful. I'm trying that solution. Could you please tell me how I can implement this? > if you got a session data , handle the redirection from there on the frontend as well Here are the context: **auth.ts** ```ts export const auth = betterAuth({ ..., socialProviders: { google: { clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, redirectURI: "http://localhost:8080/api/auth/callback/google", }, }, }); ``` **server.ts** ```ts app.all("/api/auth/*splat", toNodeHandler(auth)); ``` and I got: ``` ::1 - - [13/Apr/2025:08:29:23 +0000] "GET /api/auth/callback/google?... HTTP/1.1" 302 - "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36" ::1 - - [13/Apr/2025:08:29:23 +0000] "GET / HTTP/1.1" 404 139 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36" ``` It automatically redirects to the backend's root URL. How can I control the process after the callback is called?
Author
Owner

@Kinfe123 commented on GitHub (Apr 13, 2025):

Make sure to pass the callback url(callbackURL) on social provider config options

<!-- gh-comment-id:2799867032 --> @Kinfe123 commented on GitHub (Apr 13, 2025): Make sure to pass the callback url(`callbackURL`) on social provider config options
Author
Owner

@rinarakaki commented on GitHub (Apr 13, 2025):

It perfectly (and magically) works with this additional config:

signin/page.tsx

await authClient.signIn.social({
  provider: "google",
  callbackURL: "http://localhost:3000",
});

And it can even change callbackURL dynamically! better-auth is really a beautiful package! Thanks a lot for the help!

<!-- gh-comment-id:2799879612 --> @rinarakaki commented on GitHub (Apr 13, 2025): It perfectly (and magically) works with this additional config: **signin/page.tsx** ```ts await authClient.signIn.social({ provider: "google", callbackURL: "http://localhost:3000", }); ``` And it can even change callbackURL dynamically! better-auth is really a beautiful package! Thanks a lot for the help!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#26410