Enable token refresh
This commit is contained in:
parent
ca2eef3d08
commit
857b44d810
1 changed files with 67 additions and 33 deletions
98
auth.ts
98
auth.ts
|
@ -1,45 +1,79 @@
|
||||||
import NextAuth,{ type DefaultSession } from "next-auth";
|
import NextAuth, { type DefaultSession } from "next-auth";
|
||||||
import Authentik from "next-auth/providers/authentik";
|
import Authentik from "next-auth/providers/authentik";
|
||||||
import { PrismaAdapter } from "@auth/prisma-adapter"
|
import { PrismaAdapter } from "@auth/prisma-adapter"
|
||||||
import { PrismaClient } from "@prisma/client"
|
import { PrismaClient } from "@prisma/client"
|
||||||
|
import { JWT } from "next-auth/jwt"
|
||||||
|
|
||||||
const prisma = new PrismaClient()
|
const prisma = new PrismaClient()
|
||||||
|
|
||||||
declare module "next-auth" {
|
declare module "next-auth" {
|
||||||
interface Session {
|
interface Session {
|
||||||
access_token: string | undefined;
|
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({
|
export const { handlers, auth, signIn, signOut } = NextAuth({
|
||||||
adapter: PrismaAdapter(prisma),
|
adapter: PrismaAdapter(prisma),
|
||||||
providers: [Authentik({
|
providers: [Authentik({
|
||||||
clientId: process.env.AUTH_OIDC_CLIENT_ID,
|
clientId: process.env.AUTH_OIDC_CLIENT_ID,
|
||||||
clientSecret: process.env.AUTH_OIDC_CLIENT_SECRET,
|
clientSecret: process.env.AUTH_OIDC_CLIENT_SECRET,
|
||||||
issuer: process.env.AUTH_OIDC_ISSUER,
|
issuer: process.env.AUTH_OIDC_ISSUER,
|
||||||
authorization: { params: { scope: 'openid profile email offline_access' } },
|
authorization: { params: { scope: 'openid profile email offline_access' } },
|
||||||
})],
|
})],
|
||||||
callbacks: {
|
callbacks: {
|
||||||
async jwt({token, account}) {
|
async session({ session, user }) {
|
||||||
if (account) {
|
const [authentikAccount] = await prisma.account.findMany({
|
||||||
token = Object.assign({}, token, { access_token: account.access_token });
|
where: { userId: user.id, provider: "authentik" },
|
||||||
}
|
})
|
||||||
return token
|
|
||||||
},
|
|
||||||
async session({session, user}) {
|
|
||||||
const getToken = await prisma.account.findFirst({
|
|
||||||
where: {
|
|
||||||
userId: user.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
let accessToken: string | undefined = undefined;
|
if (authentikAccount.expires_at * 1000 < Date.now()) {
|
||||||
if (getToken) {
|
console.info("refreshing token");
|
||||||
accessToken = getToken.access_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",
|
||||||
|
})
|
||||||
|
|
||||||
session.access_token = accessToken;
|
const tokens = await response.json()
|
||||||
return session;
|
|
||||||
}
|
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),
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue