Skip to content

Commit

Permalink
fix: ensure token is not expired when calling APIs
Browse files Browse the repository at this point in the history
Refs: #95
  • Loading branch information
MaSch0212 committed Jun 23, 2024
1 parent 9ac2d25 commit a57e395
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 17 deletions.
4 changes: 2 additions & 2 deletions src/client/src/app/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ export const appConfig: ApplicationConfig = {
inject(ThemeService);

const authService = inject(AuthService);
return () => {
authService.init();
return async () => {
await authService.init();
};
},
},
Expand Down
26 changes: 17 additions & 9 deletions src/client/src/app/services/auth.interceptor.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { inject, Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { from, Observable, switchMap } from 'rxjs';

import { AuthService } from './auth.service';

Expand All @@ -9,14 +9,22 @@ export class AuthInterceptor implements HttpInterceptor {
private readonly _authService = inject(AuthService);

public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const token = this._authService.token()?.token;
if (token && !req.headers.has('Authorization')) {
req = req.clone({
setHeaders: {
Authorization: `Bearer ${token}`,
},
});
if (req.url.includes('api/auth/token')) {
return next.handle(req);
}
return next.handle(req);

return from(this._authService.ensureTokenNotExpired()).pipe(
switchMap(() => {
const token = this._authService.token()?.token;
if (token && !req.headers.has('Authorization')) {
req = req.clone({
setHeaders: {
Authorization: `Bearer ${token}`,
},
});
}
return next.handle(req);
})
);
}
}
37 changes: 31 additions & 6 deletions src/client/src/app/services/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import {
inject,
signal,
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { Router } from '@angular/router';
import { fromEvent } from 'rxjs';

import {
AuthTokenInfo,
Expand Down Expand Up @@ -47,6 +49,14 @@ export class AuthService implements OnDestroy {
this.clearTokenRefreshTimeout();
}
});

fromEvent(document, 'visibilitychange')
.pipe(takeUntilDestroyed())
.subscribe(() => {
if (!document.hidden) {
this.ensureTokenNotExpired();
}
});
}

public async init() {
Expand Down Expand Up @@ -82,6 +92,15 @@ export class AuthService implements OnDestroy {
this._token.set(null);
}

public async ensureTokenNotExpired() {
const expiration = this._token()?.expiresAt;
if (!expiration || expiration.getTime() < Date.now() + 60 * 1000) {
await this.refreshToken();
} else if (expiration) {
this.updateTokenRefreshTimeout(expiration);
}
}

public async signIn(loginToken: string): Promise<SignInResult> {
if (!environment.authenticationRequired) return 'success';

Expand Down Expand Up @@ -121,19 +140,25 @@ export class AuthService implements OnDestroy {
}

private updateTokenRefreshTimeout(expiration: Date) {
if (this._tokenRefreshTimeout) clearTimeout(this._tokenRefreshTimeout);
this._tokenRefreshTimeout = setTimeout(
() => {
const loginToken = getLoginToken();
if (loginToken) {
this.signIn(loginToken);
} else {
this.signOut();
}
this.refreshToken();
},
Math.max(10000, expiration.getTime() - Date.now() - 1000 * 60)
);
}

private async refreshToken() {
console.log('Refreshing token');
const loginToken = getLoginToken();
if (loginToken) {
await this.signIn(loginToken);
} else {
await this.signOut();
}
}

private clearTokenRefreshTimeout() {
if (this._tokenRefreshTimeout) clearTimeout(this._tokenRefreshTimeout);
this._tokenRefreshTimeout = undefined;
Expand Down

0 comments on commit a57e395

Please sign in to comment.