404 Auth Handler

I have spent hours trying to debug this, and I feel like I'm about to go crazy. I have an existing Elysia app with tRPC where I'm trying to add Better Auth. When I click my Sign Up button, I make a POST request to http://localhost:3002/api/v1/auth/sign-up/email but it returns 404. Any help would be greatly appreciated!
Solution:
SOLUTION: I simplified my Elysia app to include basically nothing but the auth view. Once I did that, I got a 403 because the origin was wrong. The culprit was simply adding baseURL: env.NEXT_PUBLIC_BASE_URL, to the Better Auth object....
Jump to solution
2 Replies
MAXXtreme
MAXXtremeOP•2w ago
Here is a simplified version of what I'm trying to get working.
// Elysia App
import { env } from '@core/env'
import { cors } from '@elysiajs/cors'
import { Elysia } from 'elysia'
import { handler as authHandler } from './v1/auth'
import { handler as trpcHandler } from './v1/trpc'

export type { V1AppRouter } from './v1/trpc/routers/v1'

new Elysia()
.use(
cors({
origin: env.NEXT_PUBLIC_BASE_URL,
credentials: true,
allowedHeaders: ['Content-Type', 'Authorization'],
}),
)
.group('/api/v1', (v1) => v1.use(authHandler).use(trpcHandler))
.listen(env.API_PORT ?? 3002)

console.log(`
API is running 🔥
API: ${env.NEXT_PUBLIC_API_URL}
Swagger: ${env.NEXT_PUBLIC_API_URL}/swagger
`)
// Elysia App
import { env } from '@core/env'
import { cors } from '@elysiajs/cors'
import { Elysia } from 'elysia'
import { handler as authHandler } from './v1/auth'
import { handler as trpcHandler } from './v1/trpc'

export type { V1AppRouter } from './v1/trpc/routers/v1'

new Elysia()
.use(
cors({
origin: env.NEXT_PUBLIC_BASE_URL,
credentials: true,
allowedHeaders: ['Content-Type', 'Authorization'],
}),
)
.group('/api/v1', (v1) => v1.use(authHandler).use(trpcHandler))
.listen(env.API_PORT ?? 3002)

console.log(`
API is running 🔥
API: ${env.NEXT_PUBLIC_API_URL}
Swagger: ${env.NEXT_PUBLIC_API_URL}/swagger
`)
// Auth handler
import { log } from '@api/lib/log'
import { auth } from '@core/auth'
import { Elysia } from 'elysia'

export const handler = new Elysia().all('/auth/*', (context) => {
log.info(context)

const BETTER_AUTH_ACCEPT_METHODS = ['POST', 'GET'] as const

if (BETTER_AUTH_ACCEPT_METHODS.includes(context.request.method))
return auth.handler(context.request)

context.error(405)
})
// Auth handler
import { log } from '@api/lib/log'
import { auth } from '@core/auth'
import { Elysia } from 'elysia'

export const handler = new Elysia().all('/auth/*', (context) => {
log.info(context)

const BETTER_AUTH_ACCEPT_METHODS = ['POST', 'GET'] as const

if (BETTER_AUTH_ACCEPT_METHODS.includes(context.request.method))
return auth.handler(context.request)

context.error(405)
})
// Better Auth
import { db } from '@core/database/client'
import { accounts, sessions, users, verifications } from '@core/database/schema'
import { betterAuth } from 'better-auth'
import { drizzleAdapter } from 'better-auth/adapters/drizzle'
import { env } from '@core/env'

export const auth = betterAuth({
baseURL: env.NEXT_PUBLIC_API_URL,
database: drizzleAdapter(db, {
provider: 'pg',
schema: {
accounts,
sessions,
users,
verifications,
},
usePlural: true,
}),
emailAndPassword: {
enabled: true,
},
})
// Better Auth
import { db } from '@core/database/client'
import { accounts, sessions, users, verifications } from '@core/database/schema'
import { betterAuth } from 'better-auth'
import { drizzleAdapter } from 'better-auth/adapters/drizzle'
import { env } from '@core/env'

export const auth = betterAuth({
baseURL: env.NEXT_PUBLIC_API_URL,
database: drizzleAdapter(db, {
provider: 'pg',
schema: {
accounts,
sessions,
users,
verifications,
},
usePlural: true,
}),
emailAndPassword: {
enabled: true,
},
})
// Better Auth React client
import { env } from '@core/env'
import { createAuthClient } from 'better-auth/react'

export const authClient = createAuthClient({
baseURL: `${env.NEXT_PUBLIC_API_URL}/api/v1/auth`,
})
// Better Auth React client
import { env } from '@core/env'
import { createAuthClient } from 'better-auth/react'

export const authClient = createAuthClient({
baseURL: `${env.NEXT_PUBLIC_API_URL}/api/v1/auth`,
})
// Sign Up Button
'use client'

import { authClient } from '@core/auth/client'
import { Button } from '@core/ui/components/ui/button'

export function SignUpButton() {
return (
<Button
onClick={async () => {
await authClient.signUp.email({
password: 'Password123',
name: 'Steve Jobs',
callbackURL: '/dashboard',
})
}}
>
Sign Up
</Button>
)
}
// Sign Up Button
'use client'

import { authClient } from '@core/auth/client'
import { Button } from '@core/ui/components/ui/button'

export function SignUpButton() {
return (
<Button
onClick={async () => {
await authClient.signUp.email({
password: 'Password123',
name: 'Steve Jobs',
callbackURL: '/dashboard',
})
}}
>
Sign Up
</Button>
)
}
Solution
MAXXtreme
MAXXtreme•2w ago
SOLUTION: I simplified my Elysia app to include basically nothing but the auth view. Once I did that, I got a 403 because the origin was wrong. The culprit was simply adding baseURL: env.NEXT_PUBLIC_BASE_URL, to the Better Auth object.

Did you find this page helpful?