web/auth.ts

86 lines
2.6 KiB
TypeScript
Raw Permalink Normal View History

2024-05-19 22:00:24 +02:00
import NextAuth from "next-auth";
2024-05-19 00:00:55 +02:00
import Authentik from "next-auth/providers/authentik";
import { PrismaAdapter } from "@auth/prisma-adapter"
import { PrismaClient } from "@prisma/client"
2024-05-19 21:34:55 +02:00
import { JWT } from "next-auth/jwt"
const prisma = new PrismaClient()
2024-05-19 00:00:55 +02:00
declare module "next-auth" {
2024-05-19 21:34:55 +02:00
interface Session {
access_token: string | undefined;
error?: "RefreshAccessTokenError"
}
2024-05-19 00:00:55 +02:00
}
2024-05-19 21:34:55 +02:00
declare module "next-auth/jwt" {
interface JWT {
access_token: string
expires_at: number
refresh_token: string
error?: "RefreshAccessTokenError"
}
}
2024-05-19 00:00:55 +02:00
export const { handlers, auth, signIn, signOut } = NextAuth({
2024-05-19 21:34:55 +02:00
adapter: PrismaAdapter(prisma),
providers: [Authentik({
clientId: process.env.AUTH_OIDC_CLIENT_ID,
clientSecret: process.env.AUTH_OIDC_CLIENT_SECRET,
issuer: process.env.AUTH_OIDC_ISSUER,
authorization: { params: { scope: 'openid profile email offline_access' } },
})],
callbacks: {
async session({ session, user }) {
const [authentikAccount] = await prisma.account.findMany({
where: { userId: user.id, provider: "authentik" },
})
let newAccessToken;
2024-05-19 21:34:55 +02:00
2024-05-19 22:00:24 +02:00
if (!authentikAccount.expires_at || !authentikAccount.refresh_token) {
throw "Expiry time or refresh token not set";
}
2024-05-19 21:34:55 +02:00
if (authentikAccount.expires_at * 1000 < Date.now()) {
console.info("refreshing token");
try {
const response = await fetch(process.env.AUTH_OIDC_TOKEN_URL!, {
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
client_id: process.env.AUTH_OIDC_CLIENT_ID!,
client_secret: process.env.AUTH_OIDC_CLIENT_SECRET!,
grant_type: "refresh_token",
refresh_token: authentikAccount.refresh_token,
}),
method: "POST",
})
2024-05-19 21:34:55 +02:00
const tokens = await response.json()
2024-05-19 21:34:55 +02:00
if (!response.ok) throw tokens
newAccessToken = tokens.access_token;
2024-05-19 21:34:55 +02:00
await prisma.account.update({
data: {
access_token: tokens.access_token,
expires_at: Math.floor(Date.now() / 1000 + tokens.expires_in),
refresh_token:
tokens.refresh_token ?? authentikAccount.refresh_token,
},
where: {
provider_providerAccountId: {
provider: "authentik",
providerAccountId: authentikAccount.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, access_token: newAccessToken ?? authentikAccount.access_token }
2024-05-19 21:34:55 +02:00
}
}
2024-05-19 00:00:55 +02:00
});