Skip to content

Instantly share code, notes, and snippets.

@mizchi
Created May 6, 2025 09:12
Show Gist options
  • Save mizchi/c726b15bced083e38ec5fdb93e6c050d to your computer and use it in GitHub Desktop.
Save mizchi/c726b15bced083e38ec5fdb93e6c050d to your computer and use it in GitHub Desktop.
/// src/auth.ts
import NextAuth, { NextAuthConfig, User } from "next-auth";
import Github from "next-auth/providers/github";
import { PrismaAdapter } from "@auth/prisma-adapter";
import { prisma } from "@/db";
export const authConfig: NextAuthConfig = {
adapter: PrismaAdapter(prisma),
providers: [
Github({
clientId: process.env.GITHUB_ID!,
clientSecret: process.env.GITHUB_SECRET!,
}),
],
secret: process.env.AUTH_SECRET,
};
export const { handlers, auth, signIn, signOut } = NextAuth(authConfig);
// src/app/dash/AuthButtons.tsx
"use client";
import { signIn, signOut } from "next-auth/react";
export function SignInButton() {
return (
<div>
<button
type="button"
onClick={() => signIn()}
className="text-white bg-blue-700 rounded-lg text-sm px-5 py-2.5 me-2 mb-2"
>
Sign In
</button>
</div>
);
}
export function SignOutButton() {
return (
<div>
<button
type="button"
onClick={() => signOut()}
className="text-white bg-red-700 rounded-lg text-sm px-5 py-2.5 me-2 mb-2"
>
Sign Out
</button>
</div>
);
}
/// src/db.ts
import { PrismaClient } from "./generated/prisma";
const globalForPrisma = globalThis as unknown as { prisma: PrismaClient };
export const prisma =
globalForPrisma.prisma ??
new PrismaClient({
log: ["query", "info", "warn", "error"],
errorFormat: "pretty",
});
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
// src/app/dash/page.tsx
import { auth } from "@/auth";
import { SignInButton, SignOutButton } from "@/app/dash/AuthButtons";
export default async function DashPage() {
const session = await auth();
return (
<div>
<h1>Dash</h1>
{session ? (
<>
<div>
<h2>Signed in</h2>
<SignOutButton />
</div>
<pre>{JSON.stringify(session, null, 2)}</pre>
</>
) : (
<div>
<h2>Not signed in</h2>
<p>Please sign in to access the dashboard.</p>
<SignInButton />
</div>
)}
</div>
);
}
/// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
previewFeatures = ["queryCompiler", "driverAdapters"]
output = "../src/generated/prisma"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(cuid())
name String?
email String @unique
emailVerified DateTime?
image String?
accounts Account[]
sessions Session[]
// Optional for WebAuthn support
Authenticator Authenticator[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Account {
userId String
type String
provider String
providerAccountId String
refresh_token String?
access_token String?
expires_at Int?
token_type String?
scope String?
id_token String?
session_state String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@id([provider, providerAccountId])
}
model Session {
sessionToken String @unique
userId String
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model VerificationToken {
identifier String
token String
expires DateTime
@@id([identifier, token])
}
// Optional for WebAuthn support
model Authenticator {
credentialID String @unique
userId String
providerAccountId String
credentialPublicKey String
counter Int
credentialDeviceType String
credentialBackedUp Boolean
transports String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@id([userId, credentialID])
}
// And add: ALTER TABLE "Session" REPLICA IDENTITY USING INDEX "Session_sessionToken_key";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment