`Angular 6 and the expiration of Jwt tokens`

I am currently developing an angular application that utilizes jwt for authenticating database calls. However, I encountered a problem where, when the token expires on the server, the app starts displaying blank pages instead of the expected data. This happens because the expired token is still stored in the local storage. After some investigation, I came across the jwt2 library which can be used to track token expiry. Even after implementing this solution, I still have to manually refresh the page to redirect to the login page. While I am able to navigate between components, I would like the login page to automatically appear or the token to be refreshed as soon as it expires. If the user attempts to move between components with an expired token, they should be redirected to the login page or have the token refreshed. I'm unsure of what else needs to be done in this situation. Any assistance would be greatly appreciated. Thank you in advance.

Below is the code snippet for my authentication guard:

Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {

  constructor(private router: Router,private authService:AuthService ){ }

  canActivate(

    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    if (!(this.authService.isTokenExpired()) ){
      // logged in so return true
      console.log("Logged IN");
      return true;
    }

    // not logged in so redirect to login page with the return url
    this.router.navigate(['/login'], { queryParams: { returnUrl: state.url } });
    return true;
  }
}

Here is the auth service implementation:


const helper = new JwtHelperService();

@Injectable({
  providedIn: 'root'
})
export class AuthService {

  constructor(private http: HttpClient) { }

  public login<T>(username: string, password: string): Observable<HttpResponse<T>> {
    let headers = new HttpHeaders();
    const clientId = 'clientid';
    const secret = 'secret';
    headers = headers.append('Authorization', 'Basic ' + btoa(`${clientId}:${secret}`));
    headers = headers.append('Content-Type', 'application/x-www-form-urlencoded');
    const params = new HttpParams().set('username', username).set('password', password).set('grant_type', 'password').set('scope', 'read');
    return this.http.post<T>('/oauth/token', params.toString(), {
      headers,
      observe: 'response'
    });
  }

  public logout<T>() {
    this.http.post('/oauth/revoke_token', '', {}).subscribe();
  }

  getToken(): string {
    return localStorage.getItem(TOKEN_NAME);
  }

  isTokenExpired(token?: string): boolean {
    if(!token) token = this.getToken();
    if(!token) return true;

    const date = helper.getTokenExpirationDate(token);
    console.log(date);
    if(date === undefined) return false;
    return !(date.valueOf() > new Date().valueOf());
  }
}

Error interceptor implementation:

@Injectable()
export class H401Interceptor implements HttpInterceptor {

    constructor(private authService: AuthService) { }

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        return next.handle(request).pipe(catchError(err => {
            if (err.status === 401) {
                // auto logout if 401 response returned from api
                // this.authService.logout();
                // location.reload(true);
                localStorage.removeItem('currentUser');
            }

            const error = err.error.message || err.statusText;
            return throwError(error);
        }));
    }
}

Answer №1

If you encounter a '401 Unauthorized' response from the backend, consider using HttpInterceptor to handle it by deleting the token and redirecting to the sign-in page. Below is an example of how this can be implemented:

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    request = request.clone({
      setHeaders: {
        Authorization: `Bearer ${this.storageService.retrieve(tokenKey)}`,
        'Content-Type': 'application/json'
      }
    });
    return next.handle(request).pipe(
      catchError((err, caught) => {
          if (err.status === 401){
            this.handleAuthError();
            return of(err);
          }
          throw err;
       })
    );
}

private handleAuthError() {
    this.storageService.delete(tokenKey);
    this.router.navigateByUrl('signIn');
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The argument type provided for returning an object in Rxjs switchmap is not valid

I have created a service in Angular that fetches data from different services and combines it with the initial service's data. If the initial service returns empty data, there is no need to call the second service. Here is the code: searchData(): Obs ...

Mocking a service dependency in Angular using Jest and Spectator during testing of a different

I am currently using: Angular CLI: 10.2.3 Node: 12.22.1 Everything is working fine with the project build and execution. I am now focusing on adding tests using Jest and Spectator. Specifically, I'm attempting to test a basic service where I can mo ...

Issues with Angular routing in Fuse administrator and user interfaces

I am encountering an issue with navigating routes for admin and user roles, where the user role has limitations compared to the admin role. <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.1/angular.min.js"></script> const ...

Exploring the power of Angular and Module Federation in SSR applications

Currently, I am utilizing angular version 13.1.0 and have successfully set up SSR by using the ng add @nguniversal/common command. In addition to that, I integrated module federation through ng add @angular-architects/<a href="/cdn-cgi/l/email-protectio ...

How can I seamlessly combine CoffeeScript and TypeScript files within a single Node.js project?

When working on a server-side node project utilizing the standard package.json structure, what is the best way to incorporate both Coffeescript and Typescript files? It's crucial that we maintain the availability of npm install, npm test, and npm sta ...

Issue: Execution terminated with error code 1: ts-node --compiler-params {"module":"CommonJS"} prisma/seed.ts

Whenever I run npx prisma db seed, I encounter the following error: Error message: 'MODULE_NOT_FOUND', requireStack: [ '/run/media/.../myapp/prisma/imaginaryUncacheableRequireResolveScript' ] } An error occurred during the execution ...

Zod vow denial: ZodError consistently delivers an empty array

My goal is to validate data received from the backend following a specific TypeScript structure. export interface Booking { locationId: string; bookingId: number; spotId: string; from: string; to: string; status: "pending" | "con ...

Having issues with parameterized URL integration between Django2 and Angular2

I am encountering an issue with integrating a URL containing parameters in Angular and Django. When making a call to the url, Django expects a slash at the end while Angular appends a question mark before the parameters. How can this be resolved? Below is ...

What steps should I take to resolve the eslint issue indicating that a TypeScript props interface is not being utilized, even though it is being used?

One of my components utilizes AvatarProps for its props: Below is the interface declaration for AvatarProps: export interface AvatarProps { userName: string; userLastName: string; userImg?: string; onPress?: Function; backgroundColorAvatar?: str ...

What's the deal with Angular query parameters and parentheses?

My Angular application has a routing structure that includes a query parameter. Here is an example: const routes: Routes = [{ path: '', component: DefaultComponent }, { path: ':uname', component: ProductDisplayComponent }]; Whe ...

Adding a new element to the div by referencing its class name

One way to add a component to the view is by using ViewContainerRef. For instance, HTML File: <div #Ref>it is possible to append the component here</div> TS File: @ViewChild("Ref", { read: ViewContainerRef }) public Ref: ViewContainerRe ...

What is the reason that Ionic Lifecycle hooks (such as ionViewWillEnter and ionViewWillLeave) do not trigger when utilized as an HTML Selector?

I have a project using Angular along with Ionic 4. I encountered an issue where the Ionic Lifecycle Hooks in the child page do not fire when it is called from the parent page's HTML using the HTML Selector. Why does this happen? How can I properly ut ...

Concerns about unchanging Behavior Subject affecting Ionic 4 interface

I have created a list program using Ionic 4 and attempted to update the list by utilizing BehaviorSubject from rxjs. The list updates properly when initialized in the ngOnInit() method, but fails to update within the add() callback. Despite logging the ou ...

utilizing express-jwt to manage unique secret passcodes on designated routes

Let me outline my scenario. Within my express app utilizing the express-jwt module, I have set up 2 key routes. It is essential for me to safeguard these routes using distinct passphrases. app.use('/api/v1/admin', jwt({secret: "blabla1"}).unles ...

Angular allows for dynamic sourcing of iframes

I have encountered an issue while trying to integrate a payment system with Angular. The payment gateway API I am using provides the 3D Secure Page as html within a JSON response. My approach is to display this html content within an iframe, however, the h ...

How to check all checkboxes in Angular using ngFor and ngIf?

Is there a way to select all checkboxes in an Angular form that uses ngFor and ngIf? I want to activate all checkboxes for the months when I click on "Select All". The list of months is stored in an array. Click here to see the HTML representation of the ...

What is the best way to store an audio Blob in the repository file system?

Currently, I have set up a system to record user audio through the device's microphone and can successfully download it on the same device. However, my goal now is to store this audio in my database by making an API call. How can I efficiently send th ...

Having trouble implementing ng2-charts in Angular 4 when using shared components

Using angular 4.0.0, angular-cli 1.2.1, and ng2-charts 1.6.0 has been a smooth experience for me so far. However, I encountered an issue when trying to incorporate ng2-charts into "shared" components. In my setup, I have a shared-components.module that is ...

When restarting the React application, CSS styles disappear from the page

While developing my React application, I encountered a problem with the CSS styling of the Select component from Material UI. Specifically, when I attempt to remove padding from the Select component, the padding is successfully removed. However, upon refre ...

Exploring the Concept of Dependency Injection in Angular 2

Below is a code snippet showcasing Angular 2/Typescript integration: @Component({ ... : ... providers: [MyService] }) export class MyComponent{ constructor(private _myService : MyService){ } someFunction(){ this._mySer ...