gursheys
gursheys
BABetter Auth
Created by gursheys on 3/8/2025 in #help
Google oauth redirecting to /api/auth
Hi, I'm setting up Google oauth in my app but when I login through google I get redirected to /api/auth (which 404s) and I can't figure out why its redirecting here. These are my network requests when logging in:
POST /api/auth/sign-in/social 200 in 514ms
GET /api/auth/callback/google?state=blGZzt7ykTo8iY1RAmeXfAKb9Yf6h6-u&code=XXXXXXXXXXXXXXXXXXXXXXXX&scope=email+profile+openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile&authuser=0&prompt=none 302 in 1235ms
GET /api/auth 404 in 228ms
POST /api/auth/sign-in/social 200 in 514ms
GET /api/auth/callback/google?state=blGZzt7ykTo8iY1RAmeXfAKb9Yf6h6-u&code=XXXXXXXXXXXXXXXXXXXXXXXX&scope=email+profile+openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile&authuser=0&prompt=none 302 in 1235ms
GET /api/auth 404 in 228ms
My setup is:
// lib/auth.ts
import { betterAuth } from 'better-auth'
import { db } from './db'
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { nextCookies } from 'better-auth/next-js';

export const auth = betterAuth({
database: drizzleAdapter(db, {
provider: "pg"
}),
socialProviders: {
google: {
clientId: process.env.GOOGLE_CLIENT_ID as string,
clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
}
},
plugins: [nextCookies()]
})
// lib/auth.ts
import { betterAuth } from 'better-auth'
import { db } from './db'
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { nextCookies } from 'better-auth/next-js';

export const auth = betterAuth({
database: drizzleAdapter(db, {
provider: "pg"
}),
socialProviders: {
google: {
clientId: process.env.GOOGLE_CLIENT_ID as string,
clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
}
},
plugins: [nextCookies()]
})
// lib/auth-client.ts
import { createAuthClient } from "better-auth/react"

export function getBaseURL() {
const baseURL =
process.env.SITE_URL || // Production
process.env.VERCEL_URL || // Preview (Vercel)
"http://localhost:3000"; // Development

return baseURL.includes("http") ? baseURL : `https://${baseURL}`;
}

export const authClient = createAuthClient({
baseURL: getBaseURL()
});
// lib/auth-client.ts
import { createAuthClient } from "better-auth/react"

export function getBaseURL() {
const baseURL =
process.env.SITE_URL || // Production
process.env.VERCEL_URL || // Preview (Vercel)
"http://localhost:3000"; // Development

return baseURL.includes("http") ? baseURL : `https://${baseURL}`;
}

export const authClient = createAuthClient({
baseURL: getBaseURL()
});
And for my login onClick I'm doing
"use client";

import Link from "next/link";
import { Icons } from "@/components/icons";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { cn } from "@/lib/utils";
import { authClient } from "@/lib/auth-client";

export function LoginComponent({ className }: { className?: string }) {
return (
<Card
className={cn(
"w-full grid md:grid-cols-3 overflow-hidden place-items-center text-center",
className
)}
>
<video
src="https://assets.clip.studio/reddit_preview.webm"
autoPlay
muted
loop
playsInline
className="col-span-1 hidden md:block w-full h-full object-cover"
/>

<div className="md:col-span-2">
<CardHeader className="flex flex-col items-center">
<Avatar className="size-24">
<AvatarImage src="/logo.svg" />
<AvatarFallback>CS</AvatarFallback>
</Avatar>
<CardTitle className="text-2xl font-medium">
Get Started with Refract
</CardTitle>
<CardDescription>
Sign in or create an account to get started
</CardDescription>
</CardHeader>
<CardContent>
<div className="grid gap-4">
<Button
variant="secondary"
className="w-full"
onClick={async () => {
await authClient.signIn.social({
provider: "google",
});
}}
>
<Icons.google className="mr-2 h-4 w-4 dark:invert" />
Login with Google
</Button>
</div>

<div className="text-[11px] text-center mt-6">
<span>By signing up, you agree to our</span>{" "}
<Link href="/terms" className="underline">
Terms
</Link>{" "}
<span>and</span>{" "}
<Link href="/privacy" className="underline">
Privacy Policy
</Link>
.
</div>
</CardContent>
</div>
</Card>
);
}
"use client";

import Link from "next/link";
import { Icons } from "@/components/icons";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { cn } from "@/lib/utils";
import { authClient } from "@/lib/auth-client";

export function LoginComponent({ className }: { className?: string }) {
return (
<Card
className={cn(
"w-full grid md:grid-cols-3 overflow-hidden place-items-center text-center",
className
)}
>
<video
src="https://assets.clip.studio/reddit_preview.webm"
autoPlay
muted
loop
playsInline
className="col-span-1 hidden md:block w-full h-full object-cover"
/>

<div className="md:col-span-2">
<CardHeader className="flex flex-col items-center">
<Avatar className="size-24">
<AvatarImage src="/logo.svg" />
<AvatarFallback>CS</AvatarFallback>
</Avatar>
<CardTitle className="text-2xl font-medium">
Get Started with Refract
</CardTitle>
<CardDescription>
Sign in or create an account to get started
</CardDescription>
</CardHeader>
<CardContent>
<div className="grid gap-4">
<Button
variant="secondary"
className="w-full"
onClick={async () => {
await authClient.signIn.social({
provider: "google",
});
}}
>
<Icons.google className="mr-2 h-4 w-4 dark:invert" />
Login with Google
</Button>
</div>

<div className="text-[11px] text-center mt-6">
<span>By signing up, you agree to our</span>{" "}
<Link href="/terms" className="underline">
Terms
</Link>{" "}
<span>and</span>{" "}
<Link href="/privacy" className="underline">
Privacy Policy
</Link>
.
</div>
</CardContent>
</div>
</Card>
);
}
7 replies