Skip to content

Commit e0fbb5f

Browse files
committed
Refresh authToken when it expires
Access tokens have lifetimes that might end before the user wants to end their authenticated session. Hence, we need to refresh the user access token after an expiry detection. Resolves: #175 Signed-off-by: fenn-cs <[email protected]>
1 parent eb4fb69 commit e0fbb5f

File tree

3 files changed

+39
-0
lines changed

3 files changed

+39
-0
lines changed

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,4 @@ PERMANENT_API_BASE_PATH=${LOCAL_TEMPORARY_AUTH_TOKEN}
4040
# See https://fusionauth.io/docs/v1/tech/apis/api-keys
4141
FUSION_AUTH_HOST=${FUSION_AUTH_HOST}
4242
FUSION_AUTH_KEY=${FUSION_AUTH_KEY}
43+
FUSION_AUTH_APP_ID=${FUSION_AUTH_APP_ID}

src/classes/AuthenticationSession.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,16 @@ enum FusionAuthStatusCode {
1515
export class AuthenticationSession {
1616
public authToken = '';
1717

18+
public refreshToken = '';
19+
20+
private authTokenExpiresAt = 0;
21+
1822
public readonly authContext;
1923

2024
private readonly fusionAuthClient;
2125

26+
private readonly fusionAuthAppId = process.env.FUSION_AUTH_APP_ID ?? '';
27+
2228
private twoFactorId = '';
2329

2430
private twoFactorMethods: TwoFactorMethod[] = [];
@@ -32,6 +38,32 @@ export class AuthenticationSession {
3238
this.promptForPassword();
3339
}
3440

41+
public obtainNewAuthTokenUsingRefreshToken(): void {
42+
this.fusionAuthClient.exchangeRefreshTokenForAccessToken(this.refreshToken, '', '', '', '')
43+
.then((clientResponse) => {
44+
this.authToken = clientResponse.response.access_token ?? '';
45+
})
46+
.catch((clientResponse: unknown) => {
47+
const message = isPartialClientResponse(clientResponse)
48+
? clientResponse.exception.message
49+
: '';
50+
logger.warn(`Error obtaining refresh token : ${message}`);
51+
this.authContext.reject();
52+
});
53+
}
54+
55+
public tokenExpired(): boolean {
56+
const expirationDate = new Date(this.authTokenExpiresAt);
57+
return expirationDate <= new Date();
58+
}
59+
60+
public tokenWouldExpireSoon(minutes = 5): boolean {
61+
const expirationDate = new Date(this.authTokenExpiresAt);
62+
const currentTime = new Date();
63+
const timeDifferenceMinutes = (expirationDate.getTime() - currentTime.getTime()) / (1000 * 60);
64+
return timeDifferenceMinutes <= minutes;
65+
}
66+
3567
private promptForPassword(): void {
3668
this.authContext.prompt(
3769
{
@@ -46,6 +78,7 @@ export class AuthenticationSession {
4678

4779
private processPasswordResponse([password]: string[]): void {
4880
this.fusionAuthClient.login({
81+
applicationId: this.fusionAuthAppId,
4982
loginId: this.authContext.username,
5083
password,
5184
}).then((clientResponse) => {
@@ -57,6 +90,8 @@ export class AuthenticationSession {
5790
username: this.authContext.username,
5891
});
5992
this.authToken = clientResponse.response.token;
93+
this.authTokenExpiresAt = clientResponse.response.tokenExpirationInstant ?? 0;
94+
this.refreshToken = clientResponse.response.refreshToken ?? '';
6095
this.authContext.accept();
6196
return;
6297
}

src/classes/SftpSessionHandler.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,9 @@ export class SftpSessionHandler {
958958
}
959959

960960
private getCurrentPermanentFileSystem(): PermanentFileSystem {
961+
if (this.authenticationSession.tokenExpired() || this.authenticationSession.tokenWouldExpireSoon()) {
962+
this.authenticationSession.obtainNewAuthTokenUsingRefreshToken();
963+
}
961964
return this.permanentFileSystemManager
962965
.getCurrentPermanentFileSystemForUser(
963966
this.authenticationSession.authContext.username,

0 commit comments

Comments
 (0)