Next Auth with Github

.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
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/userAvatar.tsx

import { auth } from "@/auth";

import * as stylex from "@stylexjs/stylex";
import { colors, size } from "../app/tokens.stylex";

const styles = stylex.create({
    avatar: {
        borderRadius: "100%",
        height: "3em",
        width: "3em",
    },
});


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","");
    return (
        <div>
            <img
                {...stylex.props(styles.avatar)}
                src={session.user && session.user.image || ""} alt="User Avatar" />
            <span>Hello {session.user.name}</span>
        </div>
    )
}

package.json

{
  "name": "next-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": {
    "@babel/runtime": "^7.26.7",
    "@mdx-js/loader": "^3.1.0",
    "@mdx-js/react": "^3.1.0",
    "@next/mdx": "^15.2.4",
    "@shikijs/rehype": "^2.2.0",
    "@stylexjs/open-props": "^0.7.5",
    "@stylexjs/stylex": "^0.7.5",
    "autoprefixer": "^10.4.20",
    "esbuild": "^0.24.2",
    "next": "^15.2.4",
    "next-auth": "5.0.0-beta.25",
    "next-view-transitions": "^0.3.4",
    "react": "^18",
    "react-dom": "^18",
    "rehype-katex": "^7.0.1",
    "remark-gfm": "^4.0.0",
    "remark-math": "^6.0.0"
  },
  "devDependencies": {
    "@stylexjs/eslint-plugin": "^0.7.5",
    "@stylexjs/postcss-plugin": "0.10.1",
    "@types/json-schema": "^7.0.15",
    "@types/mdx": "^2.0.13",
    "@types/node": "^22.7.6",
    "@types/react": "^18.3.11",
    "@types/react-dom": "^18.3.1",
    "@typescript-eslint/parser": "^6.21.0",
    "eslint": "^8.57.1",
    "eslint-config-next": "15.2.4",
    "rimraf": "^5.0.10",
    "typescript": "^5.3.3"
  }
}

app/page.tsx

import React from "react";
import stylex from "@stylexjs/stylex";

import Header from "@/components/header";
import SignIn from "@/components/signIn";
import UserAvatar from "@/components/UserAvatar";

import { colors } from "./tokens.stylex";

import { SessionProvider } from "next-auth/react";
export default async function Home() {
  return (
    <>
    <SessionProvider>
      <Header />
      <main {...stylex.props(styles.main)}>
        <div {...stylex.props(styles.content)}>
        {children} // content
        </div>
      </main>
      <div  {...stylex.props(styles.signin)}>
        <div>
          <SignIn />
          <UserAvatar />
        </div>
      </div>
      </SessionProvider>
    </>
  );
}

const styles = stylex.create({
  main: {
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
    width: "100%",
  },
  content: {
    fontFamily: "system-ui, sans-serif",
    overflow: "hidden",

    width: {
      "@media (max-width: 1400px)": "90%",
      default: "60%",
    },
    paddingBlockStart: {
      default: 16,
      "@media (min-width: 800px)": 32,
    },
    paddingBlockEnd: {
      default: 16,
      "@media (min-width: 800px)": 32,
    },
  },
  text: {
    color: colors.neutral100,
  },
  signin: {
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
    width: "100%",
  }
});

const MEDIA_MOBILE = "@media (max-width: 700px)" as const;
const MEDIA_TABLET =
  "@media (min-width: 701px) and (max-width: 1120px)" as const;