import { PrismaAdapter } from "@auth/prisma-adapter" import NextAuth, { NextAuthOptions, TokenSet, User } from "next-auth" import Github from "next-auth/providers/github" import prisma from "./prisma" import { Adapter } from "next-auth/adapters" export const authOptions: NextAuthOptions = { providers: [ Github({ clientId: process.env.GITHUB_ID as string, clientSecret: process.env.GITHUB_SECRET as string, profile(profile, tokens) { return { id: profile.id, name: profile.name, email: profile.email, image: profile.avatar_url, username: profile.login, } as User; }, }), ], adapter: PrismaAdapter(prisma) as Adapter, pages: { signIn: "/sign-in", }, session: { strategy: "jwt", }, callbacks: { session: async ({ session, token }) => { const [github] = await prisma.account.findMany({ where: { userId: session.user.id, provider: "github" }, }) if ((github.expires_at || 0) * 1000 < Date.now()) { // If the access token has expired, try to refresh it try { const params = new URLSearchParams({ client_id: process.env.GITHUB_ID as string, client_secret: process.env.GITHUB_SECRET as string, grant_type: "refresh_token", refresh_token: github.refresh_token as string, }); const response = await fetch("https://github.com/login/oauth/access_token?" + params, { headers: { "Accept": "application/json" }, method: "POST", }) const tok = await response.json() const tokens: TokenSet = tok; if (!response.ok) throw tokens await prisma.account.update({ data: { access_token: tokens.access_token, expires_at: Math.floor(Date.now() / 1000 + (tokens.expires_in as number)), refresh_token: tokens.refresh_token ?? github.refresh_token, }, where: { provider_providerAccountId: { provider: "github", providerAccountId: github.providerAccountId, }, }, }) } catch (error) { console.error("Error refreshing access token", error) // The error property will be used client-side to handle the refresh token error session.error = "RefreshAccessTokenError" } } return { ...session, user: { ...session.user, id: token.id, username: token.username, }, } }, jwt: ({ token, user }) => { if (user) { const u = user as unknown as any; return { ...token, id: u.id, username: u.username, }; } return { ...token, username: token.username }; }, }, events: { createUser: async ({ user }) => { await prisma.workspace.create({ data: { name: user.username + "'s Personal", ownerId: user.id, slug: user.username.toLowerCase(), }, }); } }, }