Skip to content

Commit a789e93

Browse files
added refresh?:boolean to getAccessToken() to force refresh AT
1 parent dbfd502 commit a789e93

File tree

2 files changed

+94
-69
lines changed

2 files changed

+94
-69
lines changed

src/server/auth-client.ts

Lines changed: 67 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -669,7 +669,8 @@ export class AuthClient {
669669
* refresh it using the refresh token, if available.
670670
*/
671671
async getTokenSet(
672-
tokenSet: TokenSet
672+
tokenSet: TokenSet,
673+
forceRefresh?: boolean | undefined
673674
): Promise<[null, TokenSet] | [SdkError, null]> {
674675
// the access token has expired but we do not have a refresh token
675676
if (!tokenSet.refreshToken && tokenSet.expiresAt <= Date.now() / 1000) {
@@ -682,68 +683,82 @@ export class AuthClient {
682683
];
683684
}
684685

685-
// the access token has expired and we have a refresh token
686-
if (tokenSet.refreshToken && tokenSet.expiresAt <= Date.now() / 1000) {
687-
const [discoveryError, authorizationServerMetadata] =
688-
await this.discoverAuthorizationServerMetadata();
686+
if (tokenSet.refreshToken) {
687+
// either the access token has expired or we are forcing a refresh
688+
if (forceRefresh || tokenSet.expiresAt <= Date.now() / 1000) {
689+
return this.refreshTokenFlow({
690+
...tokenSet,
691+
refreshToken: tokenSet.refreshToken
692+
});
693+
}
694+
}
689695

690-
if (discoveryError) {
691-
console.error(discoveryError);
692-
return [discoveryError, null];
696+
return [null, tokenSet];
697+
}
698+
699+
// refreshTokenFlow refreshes the access token using the refresh token.
700+
private async refreshTokenFlow(
701+
tokenSet: TokenSet & {
702+
refreshToken: string;
703+
}
704+
): Promise<[null, TokenSet] | [SdkError, null]> {
705+
const [discoveryError, authorizationServerMetadata] =
706+
await this.discoverAuthorizationServerMetadata();
707+
708+
if (discoveryError) {
709+
console.error(discoveryError);
710+
return [discoveryError, null];
711+
}
712+
713+
const refreshTokenRes = await oauth.refreshTokenGrantRequest(
714+
authorizationServerMetadata,
715+
this.clientMetadata,
716+
await this.getClientAuth(),
717+
tokenSet.refreshToken,
718+
{
719+
...this.httpOptions(),
720+
[oauth.customFetch]: this.fetch,
721+
[oauth.allowInsecureRequests]: this.allowInsecureRequests
693722
}
723+
);
694724

695-
const refreshTokenRes = await oauth.refreshTokenGrantRequest(
725+
let oauthRes: oauth.TokenEndpointResponse;
726+
try {
727+
oauthRes = await oauth.processRefreshTokenResponse(
696728
authorizationServerMetadata,
697729
this.clientMetadata,
698-
await this.getClientAuth(),
699-
tokenSet.refreshToken,
700-
{
701-
...this.httpOptions(),
702-
[oauth.customFetch]: this.fetch,
703-
[oauth.allowInsecureRequests]: this.allowInsecureRequests
704-
}
730+
refreshTokenRes
705731
);
732+
} catch (e: any) {
733+
console.error(e);
734+
return [
735+
new AccessTokenError(
736+
AccessTokenErrorCode.FAILED_TO_REFRESH_TOKEN,
737+
"The access token has expired and there was an error while trying to refresh it. Check the server logs for more information."
738+
),
739+
null
740+
];
741+
}
706742

707-
let oauthRes: oauth.TokenEndpointResponse;
708-
try {
709-
oauthRes = await oauth.processRefreshTokenResponse(
710-
authorizationServerMetadata,
711-
this.clientMetadata,
712-
refreshTokenRes
713-
);
714-
} catch (e: any) {
715-
console.error(e);
716-
return [
717-
new AccessTokenError(
718-
AccessTokenErrorCode.FAILED_TO_REFRESH_TOKEN,
719-
"The access token has expired and there was an error while trying to refresh it. Check the server logs for more information."
720-
),
721-
null
722-
];
723-
}
724-
725-
const accessTokenExpiresAt =
726-
Math.floor(Date.now() / 1000) + Number(oauthRes.expires_in);
727-
728-
const updatedTokenSet = {
729-
...tokenSet, // contains the existing `iat` claim to maintain the session lifetime
730-
accessToken: oauthRes.access_token,
731-
idToken: oauthRes.id_token,
732-
expiresAt: accessTokenExpiresAt
733-
};
743+
const accessTokenExpiresAt =
744+
Math.floor(Date.now() / 1000) + Number(oauthRes.expires_in);
734745

735-
if (oauthRes.refresh_token) {
736-
// refresh token rotation is enabled, persist the new refresh token from the response
737-
updatedTokenSet.refreshToken = oauthRes.refresh_token;
738-
} else {
739-
// we did not get a refresh token back, keep the current long-lived refresh token around
740-
updatedTokenSet.refreshToken = tokenSet.refreshToken;
741-
}
746+
const updatedTokenSet = {
747+
...tokenSet, // contains the existing `iat` claim to maintain the session lifetime
748+
accessToken: oauthRes.access_token,
749+
idToken: oauthRes.id_token,
750+
expiresAt: accessTokenExpiresAt
751+
};
742752

743-
return [null, updatedTokenSet];
753+
if (oauthRes.refresh_token) {
754+
// refresh token rotation is enabled, persist the new refresh token from the response
755+
updatedTokenSet.refreshToken = oauthRes.refresh_token;
756+
} else {
757+
// we did not get a refresh token back, keep the current long-lived refresh token around
758+
updatedTokenSet.refreshToken = tokenSet.refreshToken;
744759
}
745760

746-
return [null, tokenSet];
761+
return [null, updatedTokenSet];
747762
}
748763

749764
private async discoverAuthorizationServerMetadata(): Promise<

src/server/client.ts

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,9 @@ export class Auth0Client {
315315
* NOTE: Server Components cannot set cookies. Calling `getAccessToken()` in a Server Component will cause the access token to be refreshed, if it is expired, and the updated token set will not to be persisted.
316316
* It is recommended to call `getAccessToken(req, res)` in the middleware if you need to retrieve the access token in a Server Component to ensure the updated token set is persisted.
317317
*/
318-
async getAccessToken(): Promise<{ token: string; expiresAt: number }>;
318+
async getAccessToken(
319+
refresh?: boolean
320+
): Promise<{ token: string; expiresAt: number }>;
319321

320322
/**
321323
* getAccessToken returns the access token.
@@ -324,19 +326,32 @@ export class Auth0Client {
324326
*/
325327
async getAccessToken(
326328
req: PagesRouterRequest | NextRequest,
327-
res: PagesRouterResponse | NextResponse
329+
res: PagesRouterResponse | NextResponse,
330+
refresh?: boolean
328331
): Promise<{ token: string; expiresAt: number }>;
329332

330333
/**
331334
* getAccessToken returns the access token.
332-
*
333-
* NOTE: Server Components cannot set cookies. Calling `getAccessToken()` in a Server Component will cause the access token to be refreshed, if it is expired, and the updated token set will not to be persisted.
334-
* It is recommended to call `getAccessToken(req, res)` in the middleware if you need to retrieve the access token in a Server Component to ensure the updated token set is persisted.
335335
*/
336336
async getAccessToken(
337-
req?: PagesRouterRequest | NextRequest,
338-
res?: PagesRouterResponse | NextResponse
337+
reqOrRefresh?: PagesRouterRequest | NextRequest | boolean,
338+
res?: PagesRouterResponse | NextResponse,
339+
refresh?: boolean
339340
): Promise<{ token: string; expiresAt: number; scope?: string }> {
341+
// Parameter type handling
342+
let req: PagesRouterRequest | NextRequest | undefined;
343+
let actualForceRefresh: boolean | undefined;
344+
345+
// Check if the first parameter is a request object or a boolean
346+
if (typeof reqOrRefresh === "boolean" || reqOrRefresh === undefined) {
347+
// App Router case (forceRefresh as first param)
348+
actualForceRefresh = reqOrRefresh as boolean | undefined;
349+
} else {
350+
// Pages Router case (req/res as first params)
351+
req = reqOrRefresh;
352+
actualForceRefresh = refresh;
353+
}
354+
340355
const session: SessionData | null = req
341356
? await this.getSession(req)
342357
: await this.getSession();
@@ -349,26 +364,21 @@ export class Auth0Client {
349364
}
350365

351366
const [error, tokenSet] = await this.authClient.getTokenSet(
352-
session.tokenSet
367+
session.tokenSet,
368+
actualForceRefresh // Pass forceRefresh to token refresh logic
353369
);
370+
354371
if (error) {
355372
throw error;
356373
}
357374

358-
// update the session with the new token set, if necessary
375+
// Update session if token changed
359376
if (
360377
tokenSet.accessToken !== session.tokenSet.accessToken ||
361378
tokenSet.expiresAt !== session.tokenSet.expiresAt ||
362379
tokenSet.refreshToken !== session.tokenSet.refreshToken
363380
) {
364-
await this.saveToSession(
365-
{
366-
...session,
367-
tokenSet
368-
},
369-
req,
370-
res
371-
);
381+
await this.saveToSession({ ...session, tokenSet }, req, res);
372382
}
373383

374384
return {

0 commit comments

Comments
 (0)