-
-
Notifications
You must be signed in to change notification settings - Fork 21
feat: migrate from Convex Auth to Better Auth #32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
4e40722
af2d5de
70ffcb1
8870dc8
403f3b8
a00dfb5
a393324
147d0df
abe5c2b
bcb23cf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { nextJsHandler } from "@convex-dev/better-auth/nextjs"; | ||
|
||
// Export GET and POST handlers for Better Auth | ||
// This handles all auth routes like /api/auth/signin, /api/auth/callback/google, etc. | ||
export const { GET, POST } = nextJsHandler(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,8 @@ | ||
import { convexAuthNextjsToken } from "@convex-dev/auth/nextjs/server"; | ||
import { fetchMutation, fetchQuery } from "convex/nextjs"; | ||
import { PostHog } from "posthog-node"; | ||
import { z } from "zod"; | ||
import { api } from "@/convex/_generated/api"; | ||
import { getToken } from "@/lib/auth-server"; | ||
import { createErrorResponse } from "@/lib/error-utils"; | ||
|
||
export async function POST(request: Request) { | ||
|
@@ -25,11 +25,16 @@ export async function POST(request: Request) { | |
|
||
const { title, model, personaId } = parseResult.data; | ||
|
||
const token = await convexAuthNextjsToken(); | ||
const token = await getToken(); | ||
|
||
// If no valid token, the user is not authenticated | ||
if (!token) { | ||
return createErrorResponse(new Error("Unauthorized")); | ||
} | ||
Comment on lines
+31
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chainReturn explicit 401 instead of relying on Safer and clearer. If you prefer keeping Option A (explicit response here): - return createErrorResponse(new Error("Unauthorized"));
+ return new Response(
+ JSON.stringify({ error: { type: "Unauthorized", code: "UNAUTHORIZED" } }),
+ {
+ status: 401,
+ headers: {
+ "Content-Type": "application/json",
+ "WWW-Authenticate": 'Bearer realm="OpenChat", error="invalid_token"',
+ },
+ }
+ ); Option B (keep central error formatting; add a typed error):
export class UnauthorizedError extends Error {
readonly code = "UNAUTHORIZED";
constructor(message = "Unauthorized") {
super(message);
this.name = "UnauthorizedError";
}
}
export const unauthorized = (msg?: string) => new UnauthorizedError(msg);
return createErrorResponse(unauthorized()); Verify your classifier maps this to 401: 🏁 Script executed: #!/bin/bash
rg -nC5 -S 'classifyError\\s*\\(' lib/error-utils.ts Length of output: 90 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== rg createErrorResponse =="
rg -n -S -C3 'createErrorResponse' || true
echo "== rg classifyError =="
rg -n -S -C3 'classifyError' || true
echo "== rg UnauthorizedError =="
rg -n -S -C3 'UnauthorizedError' || true
echo "== rg Unauthorized =="
rg -n -S -C3 'Unauthorized' || true
echo "== file: app/api/create-chat/route.ts =="
if [ -f app/api/create-chat/route.ts ]; then sed -n '1,240p' app/api/create-chat/route.ts; else echo "MISSING: app/api/create-chat/route.ts"; fi
echo "== file: lib/error-utils.ts =="
if [ -f lib/error-utils.ts ]; then sed -n '1,240p' lib/error-utils.ts; else echo "MISSING: lib/error-utils.ts"; fi Length of output: 29256 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== lib/error-utils.ts (full) =="
sed -n '1,400p' lib/error-utils.ts || true
echo "== grep for 'unauthor' (case-insensitive) =="
rg -n --hidden -S -i 'unauthor' || true
echo "== grep for 'NotAuthenticated' / 'NOT_AUTHENTICATED' =="
rg -n --hidden -S 'NOT_AUTHENTICATED|NOT_AUTHENTICATED' || true
echo "== show createErrorResponse function region =="
rg -n --hidden -n 'export function createErrorResponse' -C5 lib/error-utils.ts || true
sed -n '270,340p' lib/error-utils.ts || true
echo "== show classifyError function region =="
rg -n --hidden -n 'export function classifyError' -C2 lib/error-utils.ts || true
sed -n '200,280p' lib/error-utils.ts || true Length of output: 20668 Return explicit 401 for unauthenticated cases (don't rely on Error("Unauthorized")) classifyError treats plain Error instances as SYSTEM_ERROR (httpStatus 500), so createErrorResponse(new Error("Unauthorized")) currently returns 500. Fix the unauthorized returns in app/api/create-chat/route.ts (lines ~31–33 and ~37–40) — change to either: Option A (explicit 401): - return createErrorResponse(new Error("Unauthorized"));
+ return new Response(
+ JSON.stringify({ error: { type: "Unauthorized", code: "UNAUTHORIZED" } }),
+ {
+ status: 401,
+ headers: {
+ "Content-Type": "application/json",
+ "WWW-Authenticate": 'Bearer realm="OpenChat", error="invalid_token"',
+ },
+ }
+ ); Option B (keep central error formatting; add a typed error):
return createErrorResponse(unauthorized()); Also update other endpoints that currently use createErrorResponse(new Error("Unauthorized")) (e.g., app/api/chat/route.ts, app/api/rate-limits/route.ts). 🤖 Prompt for AI Agents
|
||
|
||
const user = await fetchQuery(api.users.getCurrentUser, {}, { token }); | ||
|
||
// If the user is not authenticated or the token is invalid, short-circuit early | ||
// If the user is not found, return unauthorized | ||
if (!user) { | ||
return createErrorResponse(new Error("Unauthorized")); | ||
} | ||
|
Uh oh!
There was an error while loading. Please reload this page.