diff --git a/src/components/auth/SignupPage.tsx b/src/components/auth/SignupPage.tsx
new file mode 100644
index 0000000..c864ea2
--- /dev/null
+++ b/src/components/auth/SignupPage.tsx
@@ -0,0 +1,10 @@
+import { SignupForm } from './SignupForm';
+import Providers from '@/components/layout/Providers';
+
+export function SignupPage() {
+ return (
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/hooks/useAuth.ts b/src/hooks/useAuth.ts
index 9a78cec..7bab564 100644
--- a/src/hooks/useAuth.ts
+++ b/src/hooks/useAuth.ts
@@ -37,28 +37,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
const user = betterAuthSession.data?.user || null;
const session = betterAuthSession.data || null;
- // Check if this is first load and redirect if needed
- useEffect(() => {
- const checkFirstUser = async () => {
- if (!betterAuthSession.isPending && !user) {
- try {
- // Check if there are any users in the system
- const response = await fetch("/api/auth/check-users");
- if (response.status === 404) {
- // No users found, redirect to signup
- window.location.href = "/signup";
- } else if (!window.location.pathname.includes("/login")) {
- // User not authenticated, redirect to login
- window.location.href = "/login";
- }
- } catch (err) {
- console.error("Failed to check users:", err);
- }
- }
- };
-
- checkFirstUser();
- }, [betterAuthSession.isPending, user]);
+ // Don't do any redirects here - let the pages handle their own redirect logic
const login = async (email: string, password: string) => {
setIsLoading(true);
@@ -67,7 +46,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
const result = await authClient.signIn.email({
email,
password,
- callbackURL: "/dashboard",
+ callbackURL: "/",
});
if (result.error) {
@@ -93,9 +72,8 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
const result = await authClient.signUp.email({
email,
password,
- name: username, // Better Auth uses 'name' field
- username, // Also pass username as additional field
- callbackURL: "/dashboard",
+ name: username, // Better Auth uses 'name' field for display name
+ callbackURL: "/",
});
if (result.error) {
diff --git a/src/lib/auth-config.ts b/src/lib/auth-config.ts
index 1bea257..13ef64a 100644
--- a/src/lib/auth-config.ts
+++ b/src/lib/auth-config.ts
@@ -3,13 +3,6 @@ import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { sso, oidcProvider } from "better-auth/plugins";
import type { BunSQLiteDatabase } from "drizzle-orm/bun-sqlite";
-// Generate or use existing JWT secret
-const JWT_SECRET = process.env.JWT_SECRET || process.env.BETTER_AUTH_SECRET;
-
-if (!JWT_SECRET) {
- throw new Error("JWT_SECRET or BETTER_AUTH_SECRET environment variable is required");
-}
-
// This function will be called with the actual database instance
export function createAuth(db: BunSQLiteDatabase) {
return betterAuth({
diff --git a/src/lib/auth.ts b/src/lib/auth.ts
index b0ef594..d120e5f 100644
--- a/src/lib/auth.ts
+++ b/src/lib/auth.ts
@@ -1,23 +1,22 @@
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
-import { db } from "./db";
-
-// Generate or use existing JWT secret
-const JWT_SECRET = process.env.JWT_SECRET || process.env.BETTER_AUTH_SECRET;
-
-if (!JWT_SECRET) {
- throw new Error("JWT_SECRET or BETTER_AUTH_SECRET environment variable is required");
-}
+import { db, users } from "./db";
+import * as schema from "./db/schema";
+import { eq } from "drizzle-orm";
export const auth = betterAuth({
// Database configuration
database: drizzleAdapter(db, {
provider: "sqlite",
usePlural: true, // Our tables use plural names (users, not user)
+ schema, // Pass the schema explicitly
}),
+ // Secret for signing tokens
+ secret: process.env.BETTER_AUTH_SECRET,
+
// Base URL configuration
- baseURL: process.env.BETTER_AUTH_URL || "http://localhost:3000",
+ baseURL: process.env.BETTER_AUTH_URL || "http://localhost:4321",
basePath: "/api/auth", // Specify the base path for auth endpoints
// Authentication methods
@@ -30,6 +29,7 @@ export const auth = betterAuth({
console.log("Reset URL:", url);
},
},
+
// Session configuration
session: {
@@ -44,9 +44,8 @@ export const auth = betterAuth({
// Keep the username field from our existing schema
username: {
type: "string",
- required: true,
- defaultValue: "user", // Default for migration
- input: true, // Allow in signup form
+ required: false,
+ input: false, // Don't show in signup form - we'll derive from email
}
},
},
@@ -56,7 +55,7 @@ export const auth = betterAuth({
// Trusted origins for CORS
trustedOrigins: [
- process.env.BETTER_AUTH_URL || "http://localhost:3000",
+ process.env.BETTER_AUTH_URL || "http://localhost:4321",
],
});
diff --git a/src/lib/config.ts b/src/lib/config.ts
index 8968830..3929b64 100644
--- a/src/lib/config.ts
+++ b/src/lib/config.ts
@@ -18,9 +18,9 @@ export const ENV = {
return "sqlite://data/gitea-mirror.db";
},
- // JWT secret for authentication
- JWT_SECRET:
- process.env.JWT_SECRET || "your-secret-key-change-this-in-production",
+ // Better Auth secret for authentication
+ BETTER_AUTH_SECRET:
+ process.env.BETTER_AUTH_SECRET || "your-secret-key-change-this-in-production",
// Server host and port
HOST: process.env.HOST || "localhost",
diff --git a/src/lib/db/schema.ts b/src/lib/db/schema.ts
index cf84227..a400b2b 100644
--- a/src/lib/db/schema.ts
+++ b/src/lib/db/schema.ts
@@ -213,16 +213,18 @@ export const eventSchema = z.object({
export const users = sqliteTable("users", {
id: text("id").primaryKey(),
- username: text("username").notNull(),
- password: text("password").notNull(),
- email: text("email").notNull(),
+ name: text("name"),
+ email: text("email").notNull().unique(),
emailVerified: integer("email_verified", { mode: "boolean" }).notNull().default(false),
+ image: text("image"),
createdAt: integer("created_at", { mode: "timestamp" })
.notNull()
.default(sql`(unixepoch())`),
updatedAt: integer("updated_at", { mode: "timestamp" })
.notNull()
.default(sql`(unixepoch())`),
+ // Custom fields
+ username: text("username"),
});
export const events = sqliteTable("events", {
@@ -463,9 +465,10 @@ export const sessions = sqliteTable("sessions", {
// Accounts table (for OAuth providers and credentials)
export const accounts = sqliteTable("accounts", {
id: text("id").primaryKey(),
+ accountId: text("account_id").notNull(),
userId: text("user_id").notNull().references(() => users.id),
providerId: text("provider_id").notNull(),
- providerUserId: text("provider_user_id").notNull(),
+ providerUserId: text("provider_user_id"), // Make nullable for email/password auth
accessToken: text("access_token"),
refreshToken: text("refresh_token"),
expiresAt: integer("expires_at", { mode: "timestamp" }),
@@ -478,6 +481,7 @@ export const accounts = sqliteTable("accounts", {
.default(sql`(unixepoch())`),
}, (table) => {
return {
+ accountIdIdx: index("idx_accounts_account_id").on(table.accountId),
userIdIdx: index("idx_accounts_user_id").on(table.userId),
providerIdx: index("idx_accounts_provider").on(table.providerId, table.providerUserId),
};
diff --git a/src/pages/api/auth/debug.ts b/src/pages/api/auth/debug.ts
new file mode 100644
index 0000000..5dfdbc6
--- /dev/null
+++ b/src/pages/api/auth/debug.ts
@@ -0,0 +1,72 @@
+import type { APIRoute } from "astro";
+import { auth } from "@/lib/auth";
+import { db } from "@/lib/db";
+import { users } from "@/lib/db/schema";
+import { nanoid } from "nanoid";
+
+export const GET: APIRoute = async ({ request }) => {
+ try {
+ // Get Better Auth configuration info
+ const info = {
+ baseURL: auth.options.baseURL,
+ basePath: auth.options.basePath,
+ trustedOrigins: auth.options.trustedOrigins,
+ emailPasswordEnabled: auth.options.emailAndPassword?.enabled,
+ userFields: auth.options.user?.additionalFields,
+ databaseConfig: {
+ usePlural: true,
+ provider: "sqlite"
+ }
+ };
+
+ return new Response(JSON.stringify({
+ success: true,
+ config: info
+ }), {
+ status: 200,
+ headers: { "Content-Type": "application/json" },
+ });
+ } catch (error) {
+ return new Response(JSON.stringify({
+ success: false,
+ error: error instanceof Error ? error.message : "Unknown error",
+ }), {
+ status: 500,
+ headers: { "Content-Type": "application/json" },
+ });
+ }
+};
+
+export const POST: APIRoute = async ({ request }) => {
+ try {
+ // Test creating a user directly
+ const userId = nanoid();
+ const now = new Date();
+
+ await db.insert(users).values({
+ id: userId,
+ email: "test2@example.com",
+ emailVerified: false,
+ username: "test2",
+ // Let the database handle timestamps with defaults
+ });
+
+ return new Response(JSON.stringify({
+ success: true,
+ userId,
+ message: "User created successfully"
+ }), {
+ status: 200,
+ headers: { "Content-Type": "application/json" },
+ });
+ } catch (error) {
+ return new Response(JSON.stringify({
+ success: false,
+ error: error instanceof Error ? error.message : "Unknown error",
+ details: error
+ }), {
+ status: 500,
+ headers: { "Content-Type": "application/json" },
+ });
+ }
+};
\ No newline at end of file
diff --git a/src/pages/login.astro b/src/pages/login.astro
index 9ac2759..e27a6db 100644
--- a/src/pages/login.astro
+++ b/src/pages/login.astro
@@ -1,7 +1,7 @@
---
import '../styles/global.css';
import ThemeScript from '@/components/theme/ThemeScript.astro';
-import { LoginForm } from '@/components/auth/LoginForm';
+import { LoginPage } from '@/components/auth/LoginPage';
import { db, users } from '@/lib/db';
import { sql } from 'drizzle-orm';
@@ -30,7 +30,7 @@ const generator = Astro.generator;
-
+