Merged in feature/refresh-token (pull request #401)

feat: SW-101 Proactively refresh tokens

Approved-by: Michael Zetterberg
This commit is contained in:
Niclas Edenvin
2024-08-16 13:56:09 +00:00
parent 9f69e383e8
commit 819ac454b0
8 changed files with 167 additions and 67 deletions
+71 -65
View File
@@ -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: {