fix(auth): return 403 instead of 500 for blocked sign-in/sign-up attempts (#4783)

The hooks.before middleware threw plain Errors for the four auth-policy
gates (registration disabled, email/password disabled, login allowlist,
blocked signup domains). better-auth surfaces an uncaught hook Error as a
generic 500 SERVER_ERROR, so users hitting these gates saw 'Failed to
create account' with no actionable message.

Throw APIError('FORBIDDEN', { message }) instead so the endpoints return a
clean 403 with the policy message, which the client surfaces directly.

Internal/server failures (email send, provider userinfo fetch, ID-token
parse) intentionally remain plain Errors so they continue to surface as
500s.
This commit is contained in:
Waleed
2026-05-28 17:39:20 -07:00
committed by GitHub
parent 2ede04dfe0
commit 2490a3c37c
+13 -5
View File
@@ -9,7 +9,7 @@ import { toError } from '@sim/utils/errors'
import { generateId } from '@sim/utils/id'
import { betterAuth } from 'better-auth'
import { drizzleAdapter } from 'better-auth/adapters/drizzle'
import { createAuthMiddleware } from 'better-auth/api'
import { APIError, createAuthMiddleware } from 'better-auth/api'
import { nextCookies } from 'better-auth/next-js'
import {
admin,
@@ -793,12 +793,16 @@ export const auth = betterAuth({
hooks: {
before: createAuthMiddleware(async (ctx) => {
if (ctx.path.startsWith('/sign-up') && isRegistrationDisabled)
throw new Error('Registration is disabled, please contact your admin.')
throw new APIError('FORBIDDEN', {
message: 'Registration is disabled, please contact your admin.',
})
if (!isEmailPasswordEnabled) {
const emailPasswordPaths = ['/sign-in/email', '/sign-up/email', '/email-otp']
if (emailPasswordPaths.some((path) => ctx.path.startsWith(path)))
throw new Error('Email/password authentication is disabled. Please use SSO to sign in.')
throw new APIError('FORBIDDEN', {
message: 'Email/password authentication is disabled. Please use SSO to sign in.',
})
}
if (
@@ -826,13 +830,17 @@ export const auth = betterAuth({
}
if (!isAllowed) {
throw new Error('Access restricted. Please contact your administrator.')
throw new APIError('FORBIDDEN', {
message: 'Access restricted. Please contact your administrator.',
})
}
}
}
if (ctx.path.startsWith('/sign-up') && isSignupEmailBlocked(ctx.body?.email)) {
throw new Error('Sign-ups from this email domain are not allowed.')
throw new APIError('FORBIDDEN', {
message: 'Sign-ups from this email domain are not allowed.',
})
}
if (ctx.path === '/oauth2/authorize' || ctx.path === '/oauth2/token') {