[GH-ISSUE #2088] ctx.redirect doesn't redirect to custom url in databaseHooks #9045

Closed
opened 2026-04-13 04:19:59 -05:00 by GiteaMirror · 4 comments
Owner

Originally created by @showduhtung on GitHub (Apr 2, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/2088

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. Setup config:
databaseHooks: {
  user: {
    create: {
      before: async (user, ctx) => {
        const foundUser = await prisma.user.findUnique({
          where: { email: user.email },
        });
        if (!ctx) {
          throw new Error("Context is undefined");
        }
        if (foundUser === null) {
          throw ctx.redirect("/auth/error?error=Unauthorized");
        }
        return { ...ctx, data: user };
      },
    },
  },
},
  1. Go through login flow

Current vs. Expected behavior

Expected Behavior

When a user attempts to log in but doesn't exist in the database, they should be redirected to my custom error page at /auth/error?error=Unauthorized.

Current Behavior

Despite throwing ctx.redirect, users are still being sent to better-auth's default error page rather than my custom error page.

What version of Better Auth are you using?

1.1.17

Provide environment information

- OS: MacOS
- Browser: [Arc, Chrome]
- Framework: Next.js 15.2.4

Which area(s) are affected? (Select all that apply)

Client, Backend

Auth config (if applicable)

const auth = betterAuth({
  database: prismaAdapter(prisma, { provider: "postgresql" }),
  emailAndPassword: { enabled: false },
  socialProviders: {
    discord: { clientId: env.DISCORD_CLIENT_ID, clientSecret: env.DISCORD_CLIENT_SECRET },
  },

  databaseHooks: {
    user: {
      create: {
        before: async (user, ctx) => {
          const foundUser = await prisma.user.findUnique({
            where: { email: user.email },
          });

          if (!ctx) {
            throw new Error("Context is undefined");
          }

          if (foundUser === null) {
            throw ctx.redirect("/auth/error?error=Unauthorized");
          }
          return { ...ctx, data: user };
        },
      },
    },
  },
  ...options,
  plugins: [
    customSession(
      // eslint-disable-next-line @typescript-eslint/require-await
      async (args) => args,
      options,
    ),
  ],
});

Additional context

Description

I'm trying to redirect users to a custom error page when they attempt to log in but don't exist in my database. However, ctx.redirect doesn't seem to work as expected in the before hook of databaseHooks.user.create. I'm aware that there's an admin plugin or I could create a custom plugin, but this seems like it should be a simple redirect functionality. Any help would be greatly appreciated!

Originally created by @showduhtung on GitHub (Apr 2, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/2088 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. Setup config: ``` databaseHooks: { user: { create: { before: async (user, ctx) => { const foundUser = await prisma.user.findUnique({ where: { email: user.email }, }); if (!ctx) { throw new Error("Context is undefined"); } if (foundUser === null) { throw ctx.redirect("/auth/error?error=Unauthorized"); } return { ...ctx, data: user }; }, }, }, }, ``` 2. Go through login flow ### Current vs. Expected behavior ### Expected Behavior When a user attempts to log in but doesn't exist in the database, they should be redirected to my custom error page at /auth/error?error=Unauthorized. ### Current Behavior Despite throwing ctx.redirect, users are still being sent to better-auth's default error page rather than my custom error page. ### What version of Better Auth are you using? 1.1.17 ### Provide environment information ```bash - OS: MacOS - Browser: [Arc, Chrome] - Framework: Next.js 15.2.4 ``` ### Which area(s) are affected? (Select all that apply) Client, Backend ### Auth config (if applicable) ```typescript const auth = betterAuth({ database: prismaAdapter(prisma, { provider: "postgresql" }), emailAndPassword: { enabled: false }, socialProviders: { discord: { clientId: env.DISCORD_CLIENT_ID, clientSecret: env.DISCORD_CLIENT_SECRET }, }, databaseHooks: { user: { create: { before: async (user, ctx) => { const foundUser = await prisma.user.findUnique({ where: { email: user.email }, }); if (!ctx) { throw new Error("Context is undefined"); } if (foundUser === null) { throw ctx.redirect("/auth/error?error=Unauthorized"); } return { ...ctx, data: user }; }, }, }, }, ...options, plugins: [ customSession( // eslint-disable-next-line @typescript-eslint/require-await async (args) => args, options, ), ], }); ``` ### Additional context ### Description I'm trying to redirect users to a custom error page when they attempt to log in but don't exist in my database. However, ctx.redirect doesn't seem to work as expected in the before hook of databaseHooks.user.create. I'm aware that there's an admin plugin or I could create a custom plugin, but this seems like it should be a simple redirect functionality. Any help would be greatly appreciated!
GiteaMirror added the lockedbug labels 2026-04-13 04:19:59 -05:00
Author
Owner

@showduhtung commented on GitHub (Apr 2, 2025):

Note, I've tried to use the onApiError option, (https://www.better-auth.com/docs/reference/options#onapierror), and it seems like this option doesn't apply on a thrown ApiError in databaseHooks

<!-- gh-comment-id:2772521207 --> @showduhtung commented on GitHub (Apr 2, 2025): Note, I've tried to use the `onApiError` option, (https://www.better-auth.com/docs/reference/options#onapierror), and it seems like this option doesn't apply on a thrown ApiError in `databaseHooks`
Author
Owner

@s3f5 commented on GitHub (Apr 6, 2025):

@showduhtung to disable a sign up for new users you could use => disableSignUp or disableImplicitSignUp on the provider and create a custom error page for /auth/error?error=signup_disabled.

<!-- gh-comment-id:2781322043 --> @s3f5 commented on GitHub (Apr 6, 2025): @showduhtung to disable a sign up for new users you could use => [disableSignUp or disableImplicitSignUp](https://www.better-auth.com/docs/concepts/oauth#other-provider-configurations) on the provider and create a custom error page for /auth/error?error=signup_disabled.
Author
Owner

@Bekacru commented on GitHub (Apr 12, 2025):

this should work properly staring from 1.2.6-beta.13

<!-- gh-comment-id:2799038711 --> @Bekacru commented on GitHub (Apr 12, 2025): this should work properly staring from `1.2.6-beta.13`
Author
Owner

@showduhtung commented on GitHub (Apr 18, 2025):

@showduhtung to disable a sign up for new users you could use => disableSignUp or disableImplicitSignUp on the provider and create a custom error page for /auth/error?error=signup_disabled.

Oh disableImplicitSignUp looks quite promising. I think it won't fully cover my problem where I want to conditionally redirect to a custom error page, but it seems helpful. I'll give it a try

<!-- gh-comment-id:2814605953 --> @showduhtung commented on GitHub (Apr 18, 2025): > [@showduhtung](https://github.com/showduhtung) to disable a sign up for new users you could use => [disableSignUp or disableImplicitSignUp](https://www.better-auth.com/docs/concepts/oauth#other-provider-configurations) on the provider and create a custom error page for /auth/error?error=signup_disabled. Oh `disableImplicitSignUp ` looks quite promising. I think it won't fully cover my problem where I want to conditionally redirect to a custom error page, but it seems helpful. I'll give it a try
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#9045