web/auth.ts
GHOSCHT 383b84d103
Use right access token in session after refresh
previously the old token was still being used in the session even though a new one has been saved in the database
2024-05-19 22:26:43 +02:00

85 lines
2.6 KiB
TypeScript

import NextAuth from "next-auth";
import Authentik from "next-auth/providers/authentik";
import { PrismaAdapter } from "@auth/prisma-adapter"
import { PrismaClient } from "@prisma/client"
import { JWT } from "next-auth/jwt"
const prisma = new PrismaClient()
declare module "next-auth" {
interface Session {
access_token: string | undefined;
error?: "RefreshAccessTokenError"
}
}
declare module "next-auth/jwt" {
interface JWT {
access_token: string
expires_at: number
refresh_token: string
error?: "RefreshAccessTokenError"
}
}
export const { handlers, auth, signIn, signOut } = NextAuth({
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;
if (!authentikAccount.expires_at || !authentikAccount.refresh_token) {
throw "Expiry time or refresh token not set";
}
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",
})
const tokens = await response.json()
if (!response.ok) throw tokens
newAccessToken = tokens.access_token;
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 }
}
}
});