Next Auth with Github
Server Side Authentication with NextAuth.js and GitHub
https://authjs.dev/getting-started/session-management/protecting
https://authjs.dev/getting-started/migrating-to-v5#authenticating-server-side
.env.local
AUTH_SECRET="changemefajsflajsflajksf;laj=" # Added by `npx auth secret`. Read more: https://cli.authjs.dev
GITHUB_ID=3123123123example
GITHUB_SECRET=3123123123example3123123123example
app/api/auth/[...nextauth]/route.ts
import { handlers } from "@/auth" // Referring to the auth.ts we just created
export const { GET, POST } = handlers
auth.ts
import NextAuth from "next-auth"
import GitHubProvider from "next-auth/providers/github";
if (!process.env.GITHUB_ID || !process.env.GITHUB_SECRET)
throw new Error("Failed to initialize Github authentication");
if (!process.env.AUTH_SECRET)
throw new Error("Failed to find AUTH_SECRET, run `npx auth secret` and add to .env.local or prod/preview credentials");
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [
GitHubProvider({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET,
// the below doesn't seem to work
//
// profile(profile) {
// return {
// id: profile.id.toString(),
// name: profile.name || profile.login,
// gh_username: profile.login,
// email: profile.email,
// image: profile.avatar_url
// };
// }
//
// instead I get
//
// {
// user: {
// name: 'Ian Cleary',
// email: 'redacted@redacted.com',
// image: 'https://avatars.githubusercontent.com/u/12312redacted123123?v=4'
// },
// expires: '2025-05-17T04:15:53.305Z'
// }
// as the session
}),
],
})
components/auth/userAvatar.tsx
import { auth } from "@/auth";
import Image from "next/image";
export default async function UserAvatar() {
const session = await auth()
if (!session?.user) return null
console.log(session);
// {
// user: {
// name: 'Ian Cleary',
// email: 'redacted@redacted.com',
// image: 'https://avatars.githubusercontent.com/u/12312redacted123123?v=4'
// },
// expires: '2025-05-17T04:15:53.305Z'
// }
// const userIdWithParams = session.user?.image?.replace("https://avatars.githubusercontent.com/u/","");
// const userId = userIdWithParams?.replace("?v=4","");
if (!session?.user) {
return (
<div className="rounded-full mt-1 bg-neutral-950 h-8 w-8 border-0">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className="size-8"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M17.982 18.725A7.488 7.488 0 0 0 12 15.75a7.488 7.488 0 0 0-5.982 2.975m11.963 0a9 9 0 1 0-11.963 0m11.963 0A8.966 8.966 0 0 1 12 21a8.966 8.966 0 0 1-5.982-2.275M15 9.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"
/>
</svg>
</div>
);
}
return (
<div>
<Image
className="rounded-full bg-neutral-950 border-0"
src={(session.user && session.user.image) || ""}
alt="User Avatar"
width={32}
height={32}
/>
{/* <span>Hello {session.user.name}</span> */}
</div>
);
}
signIn.tsx
"use client";
import { useSession, signIn, signOut } from "next-auth/react";
export default function SignIn() {
const { data: session } = useSession();
if (session) {
return (
<div className="p-8 bg-neutral-600">
{/* Signed in as {session.user.name} <br />{" "} */}
<button onClick={() => signOut()}>Sign out</button>
</div>
);
}
return (
<div className="p-4 bg-neutral-600 rounded-md">
<button className="rounded bg-neutral-700 w-full mb-2" onClick={() => signIn()}><div className="m-2">Sign in</div></button>
<i className="">(Only works for Ian Cleary)</i>
</div>
);
}
package.json
{
"name": "next-auth-example",
"version": "0.0.0",
"private": true,
"scripts": {
"clean": "rimraf .next",
"dev": "next dev",
"build": "next build",
"start": "next start",
"next:lint": "next lint"
},
"dependencies": {
// ...
"next": "^15.4.1",
"next-auth": "5.0.0-beta.27",
//...
},
"devDependencies": {
// ...
}
}