Merged in feature/refresh-token (pull request #401)
feat: SW-101 Proactively refresh tokens Approved-by: Michael Zetterberg
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
import NextAuth from "next-auth"
|
||||
|
||||
import { PRE_REFRESH_TIME_IN_SECONDS } from "@/constants/auth"
|
||||
import { env } from "@/env/server"
|
||||
|
||||
import { LoginTypeEnum } from "./types/components/tracking"
|
||||
|
||||
import type { NextAuthConfig, User } from "next-auth"
|
||||
import type { JWT } from "next-auth/jwt"
|
||||
import type { OIDCConfig } from "next-auth/providers"
|
||||
|
||||
function getLoginType(user: User) {
|
||||
@@ -20,6 +22,66 @@ function getLoginType(user: User) {
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshTokens(token: JWT) {
|
||||
try {
|
||||
console.log("token-debug Access token expired, trying to refresh it.", {
|
||||
expires_at: token.expires_at,
|
||||
sub: token.sub,
|
||||
token: token.access_token,
|
||||
})
|
||||
const response = await fetch(`${env.CURITY_ISSUER_USER}/oauth/v2/token`, {
|
||||
body: new URLSearchParams({
|
||||
client_id: env.CURITY_CLIENT_ID_USER,
|
||||
client_secret: env.CURITY_CLIENT_SECRET_USER,
|
||||
grant_type: "refresh_token",
|
||||
refresh_token: token.refresh_token,
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
method: "POST",
|
||||
})
|
||||
|
||||
const new_tokens = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
console.log("token-debug Token response was not ok", {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
sub: token.sub,
|
||||
})
|
||||
throw new_tokens
|
||||
}
|
||||
|
||||
console.log("token-debug Successfully got new token(s)", {
|
||||
expires_at: new_tokens.expires_at,
|
||||
got_new_refresh_token: new_tokens.refresh_token !== token.refresh_token,
|
||||
got_new_access_token: new_tokens.access_token !== token.access_token,
|
||||
sub: token.sub,
|
||||
})
|
||||
|
||||
const expiresAt = new_tokens.expires_in
|
||||
? Date.now() + new_tokens.expires_in * 1000
|
||||
: undefined
|
||||
|
||||
return {
|
||||
...token,
|
||||
access_token: new_tokens.access_token,
|
||||
expires_at: expiresAt,
|
||||
refresh_token: new_tokens.refresh_token,
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("token-debug Error thrown when trying to refresh", {
|
||||
error,
|
||||
sub: token.sub,
|
||||
})
|
||||
return {
|
||||
...token,
|
||||
error: "RefreshAccessTokenError" as const,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const curityProvider = {
|
||||
id: "curity",
|
||||
name: "Curity",
|
||||
@@ -103,7 +165,7 @@ export const config = {
|
||||
async authorized({ auth, request }) {
|
||||
return true
|
||||
},
|
||||
async jwt({ account, token, trigger, user, profile }) {
|
||||
async jwt({ account, session, token, trigger, user, profile }) {
|
||||
const loginType = getLoginType(user)
|
||||
if (trigger === "signIn" && account) {
|
||||
const mfa_scope =
|
||||
@@ -121,71 +183,15 @@ export const config = {
|
||||
mfa_scope: mfa_scope,
|
||||
mfa_expires_at: mfa_expires_at,
|
||||
}
|
||||
} else if (Date.now() < token.expires_at) {
|
||||
return token
|
||||
} else {
|
||||
try {
|
||||
console.log(
|
||||
"token-debug Access token expired, trying to refresh it.",
|
||||
{
|
||||
expires_at: token.expires_at,
|
||||
sub: token.sub,
|
||||
token: token.access_token,
|
||||
}
|
||||
)
|
||||
const response = await fetch(
|
||||
`${env.CURITY_ISSUER_USER}/oauth/v2/token`,
|
||||
{
|
||||
body: new URLSearchParams({
|
||||
client_id: env.CURITY_CLIENT_ID_USER,
|
||||
client_secret: env.CURITY_CLIENT_SECRET_USER,
|
||||
grant_type: "refresh_token",
|
||||
refresh_token: token.refresh_token,
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
method: "POST",
|
||||
}
|
||||
)
|
||||
|
||||
const new_tokens = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
console.log("token-debug Token response was not ok", {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
sub: token.sub,
|
||||
})
|
||||
throw new_tokens
|
||||
}
|
||||
|
||||
console.log("token-debug Successfully got new token(s)", {
|
||||
expires_at: new_tokens.expires_at,
|
||||
got_new_refresh_token:
|
||||
new_tokens.refresh_token !== token.refresh_token,
|
||||
got_new_access_token:
|
||||
new_tokens.access_token !== token.access_token,
|
||||
sub: token.sub,
|
||||
})
|
||||
|
||||
return {
|
||||
...token,
|
||||
access_token: new_tokens.access_token,
|
||||
expires_at: new_tokens.expires_at,
|
||||
refresh_token: new_tokens.refresh_token ?? token.refresh_token,
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("token-debug Error thrown when trying to refresh", {
|
||||
error,
|
||||
sub: token.sub,
|
||||
})
|
||||
return {
|
||||
...token,
|
||||
error: "RefreshAccessTokenError" as const,
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
token.expires_at &&
|
||||
Date.now() > token.expires_at - PRE_REFRESH_TIME_IN_SECONDS * 1000 &&
|
||||
session?.doRefresh
|
||||
) {
|
||||
return refreshTokens(token)
|
||||
}
|
||||
|
||||
return token
|
||||
},
|
||||
},
|
||||
// events: {
|
||||
|
||||
Reference in New Issue
Block a user