For https://github.com/yusukebe/hono-vite-react-stack
npm install better-auth
Add authentication tables to your schema file (src/lib/schema.ts
):
users
- Store user informationaccounts
- Manage login methods and credentialssessions
- Track active login sessionsverifications
- Handle email verification tokensimport { sql } from 'drizzle-orm';
import { text, integer, sqliteTable } from 'drizzle-orm/sqlite-core';
export const users = sqliteTable("user", {
id: text("id").primaryKey(),
name: text("name").notNull(),
email: text("email").notNull(),
emailVerified: integer("email_verified", { mode: 'boolean' }).notNull(),
image: text("image"),
createdAt: integer("created_at", { mode: 'timestamp' }).notNull().default(sql`CURRENT_TIMESTAMP`),
updatedAt: integer("updated_at", { mode: 'timestamp' }).notNull().default(sql`CURRENT_TIMESTAMP`),
});
export const accounts = sqliteTable("account", {
id: text("id").primaryKey(),
userId: text("user_id").notNull().references(() => users.id),
accountId: text("account_id").notNull(),
providerId: text("provider_id").notNull(),
accessToken: text("access_token"),
refreshToken: text("refresh_token"),
accessTokenExpiresAt: integer("access_token_expires_at", { mode: 'timestamp' }),
refreshTokenExpiresAt: integer("refresh_token_expires_at", { mode: 'timestamp' }),
scope: text("scope"),
idToken: text("id_token"),
password: text("password"),
createdAt: integer("created_at", { mode: 'timestamp' }).notNull().default(sql`CURRENT_TIMESTAMP`),
updatedAt: integer("updated_at", { mode: 'timestamp' }).notNull().default(sql`CURRENT_TIMESTAMP`),
});
export const sessions = sqliteTable("session", {
id: text("id").primaryKey(),
userId: text("user_id").notNull().references(() => users.id),
token: text("token").notNull(),
expiresAt: integer("expires_at", { mode: 'timestamp' }).notNull(),
ipAddress: text("ip_address"),
userAgent: text("user_agent"),
createdAt: integer("created_at", { mode: 'timestamp' }).notNull().default(sql`CURRENT_TIMESTAMP`),
updatedAt: integer("updated_at", { mode: 'timestamp' }).notNull().default(sql`CURRENT_TIMESTAMP`),
});
export const verifications = sqliteTable("verification", {
id: text("id").primaryKey(),
identifier: text("identifier").notNull(),
value: text("value").notNull(),
expiresAt: integer("expires_at", { mode: 'timestamp' }).notNull(),
createdAt: integer("created_at", { mode: 'timestamp' }).notNull().default(sql`CURRENT_TIMESTAMP`),
updatedAt: integer("updated_at", { mode: 'timestamp' }).notNull().default(sql`CURRENT_TIMESTAMP`),
});
The auth instance is created based on env.
Create src/lib/auth.ts
to configure the auth provider:
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { Env, getDb } from "@/server/db";
import { users, accounts, sessions, verifications } from "@/lib/schema";
export const getAuth = (env: Env) => {
return betterAuth({
database: drizzleAdapter(getDb(env), {
provider: "sqlite",
schema: {
user: users,
account: accounts,
session: sessions,
verification: verifications
}
}),
emailAndPassword: {
enabled: true,
},
// Uncomment to enable social login
// socialProviders: {
// github: {
// clientId: process.env.GITHUB_CLIENT_ID as string,
// clientSecret: process.env.GITHUB_CLIENT_SECRET as string,
// },
// }
});
};
Create authentication middleware (src/server/middleware.ts
):
import { getAuth } from "@/lib/auth";
export const authMiddleware = async (c, next) => {
const auth = getAuth(c.env);
const session = await auth.api.getSession(c.req.raw);
if (!session && c.req.method === "POST") {
return c.json({ error: "Unauthorized" }, 401);
}
c.set("session", session);
await next();
};
Configure auth routes in main server file (src/server/index.tsx
):
app.on(["POST", "GET"], "/api/auth/*", async (c) => {
const auth = getAuth(c.env);
return auth.handler(c.req.raw);
});
Protect routes with middleware:
app.use("/api/listings", authMiddleware);
Create src/lib/auth-client.ts
:
import { createAuthClient } from "better-auth/react";
export const authClient = createAuthClient({});
export const {
signIn,
signUp,
signOut,
useSession
} = authClient;
Add any required auth-related environment variables (for social providers, etc.)
Add this context to your project via the
ctxs
command line integration: