frontend/lib/nextauth.ts

108 lines
3.8 KiB
TypeScript

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"
import { createWorkspace } from "./deploy/workspace"
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 }) => {
const worksapce = await prisma.workspace.create({
data: {
name: user.username + "'s Personal",
ownerId: user.id,
slug: user.username.toLowerCase(),
},
});
}
},
}