The initial invocation of OidcSecurityService.getAccessToken() returns null as the token

Our internal application requires all users to be authenticated and authorized, including for the home page. To achieve this, we use an HttpInterceptor to add a bearer token to our API requests.

Initially, when rendering the first set of data with the first API call, the token is null. The token remains null even after receiving it from the getAccessToken() subscription. However, subsequent API calls work fine, even if the user refreshes the page (F5).

We are currently using angular 16.1 along with [email protected]. This issue arose when we upgraded from a previous version of angular-auth-oidc-client that did not utilize rxjs subscribe.

import { Injectable, Injector } from "@angular/core";
import { Observable } from "rxjs";
import {
  HttpInterceptor,
  HttpEvent,
  HttpRequest,
  HttpHandler,
} from "@angular/common/http";
import { OidcSecurityService } from "angular-auth-oidc-client";
import { Router } from "@angular/router";
import { TokenValidatorService } from "../../services/token-validator.service";

export const UseOidcInterceptorHeader = "X-Oidc-Interceptor";

@Injectable()
export class TokenInterceptor implements HttpInterceptor {
  token = null;
  constructor(
    public oidcSecurityService: OidcSecurityService,
    private tokenValidatorService: TokenValidatorService,
    private router: Router
  ) {
    this.oidcSecurityService.getAccessToken().subscribe((token) => {
      this.token = token
    });
  }

  intercept(
    req: HttpRequest<unknown>,
    next: HttpHandler
  ): Observable<HttpEvent<unknown>> {
    // we do not intercept authentication calls to "companyAuthServer"
    if (req.url.includes("companyAuthServer")) {
      return next.handle(req);
    }

    if (this.token !== null) {
      if (!this.tokenValidatorService.checkUserIsInAdGroup(this.token)) {
        this.router.navigate(["/oidc/unauthorized"]);
      }

      const requestForward = req.clone({
        setHeaders: { Authorization: "Bearer " + this.token },
      });

      return next.handle(requestForward);
    } else {
      console.error(
        "OidcSecurityService, token not fetched: NO authorize header!",
        req.urlWithParams
      );
    }
    return next.handle(req);
  }
}

Answer №1

Asynchronous results in the constructor can cause issues if not handled correctly. When you subscribe and store the async result in this.token, it won't be set by the time intercept() is first called.

To avoid this problem, you can return an observable that waits for the async call to complete before proceeding with the next request:

intercept(req: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
  if (req.url.includes("companyAuthServer")) {
    return next.handle(req);
  }

  return this.oidcSecurityService.getAccessToken().pipe(
    tap(token => {
      if(!token || !this.tokenValidatorService.checkUserIsInAdGroup(token)) {
        this.router.navigate(["/oidc/unauthorized"]);
      }
    }),
    map(token => req.clone({ setHeaders: { Authorization: `Bearer ${token}` }}),
    switchMap(authRequest => next.handle(authRequest))
  );
}

Please note that this code snippet has not been tested, so some adjustments may be necessary. However, it should provide a good starting point for your implementation.

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

Having trouble resolving npm install -g @angular/cli due to issue with checking the installable status of [email protected] module

When attempting to install @angular/cli using the npm command in the command prompt, I encountered an issue with resolveWithNewModule. It seems to be stuck at checking installable status.[email protected] ...

Theme customization in Material UI includes the addition of a custom color. However, this custom color is missing from the control values in Story

Currently in my project, I am utilizing a stack that includes React 18, TypeScript, MUI 5, and Storybook 6.5. I have been attempting to incorporate custom colors into my MUI Theme and have them reflect in Storybook's dropdown options for the color p ...

The Angular JavaScript page successfully compiles, yet displays only a blank screen

I am facing an issue with my Angular app where it compiles successfully, but the HTML page appears blank and my application is not displaying properly. I have encountered similar problems in the past which were often related to Imports, but this time I&apo ...

Passing data through Angular2 router: a comprehensive guide

I am currently developing a web application with the latest version of Angular (Angular v2.0.0). In my app, I have a sub-navigation and I want to pass data to a sub-page that loads its own component through the router-outlet. According to Angular 2 docume ...

Transferring pictures between folders

I am currently developing an Angular app that involves working with two images: X.png and Y.png. My goal is to copy these images from the assets folder to a specific location on the C drive (c:\users\images) whose path is received as a variable. ...

Async function is improperly updating the array state by overwriting it completely instead of just updating one item as

I am working on a file upload feature where each uploaded file should have a progress bar that updates as the file gets uploaded. I'm using a state to keep track of selected files and their respective progress: interface IFiles { file: File; c ...

Developing an angular progress bar

I've been working on creating a progress bar in Angular using the mmat-stepper. Here's a snippet of my code: import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppCom ...

unable to retrieve information from the redis cache

Attempting to retrieve data from cache using the readData function in the controller file. Encountering an issue where the someVal variable is initially undefined after calling readData, but eventually gets populated with data after receiving a callback ...

Display no data when filters in ag-grid are empty

I'm currently utilizing the free version of ag-grid with AngularJS. Is there a way to display row data only when a filter contains content? I've gone through all the documentation, including gridoptions, but haven't been able to find a solu ...

Guide for registering to modifications of a single key within a form group in Angular 2

I am facing an issue with my userForm group that consists of keys name, email, and phone. I have implemented an onValueChanged function to validate these fields whenever they are changed. However, the validation runs every time even if the field has not ...

How can I activate TypeScript interface IntelliSense for React projects in VSCode?

Did you know that there are TypeScript interfaces designed for DOM, ES5, and other JavaScript modules? I am curious if it is feasible to have intellisense similar to the one provided by TypeScript Playground for various interfaces in a React project. ...

Difficulty with Ionic: unable to compile for android

I am currently working on an Ionic 3.4 project and trying to build it for Android testing. Following the installation of Android Studio, the Android SDK, and Java 8, I proceeded with the command: ionic cordova platform add android However, when I atte ...

Utilizing TypedPropertyDescriptor to limit decorators in Typescript when using decorator factories

When it comes to restricting what a decorator can apply on, the standard method involves using a TypedPropertyDescriptor like so: export function decorator(target, key, TypedPropertyDescriptor<T extends ...>) {...} While this approach works well whe ...

Could you explain the meaning of the :host /deep/ selector?

Can you provide a simple explanation of what the :host /deep/ selector does? :host /deep/ .ui-autocomplete { width: 85%; } ...

Spread an all-encompassing category across a collection

What is the method in TypeScript to "spread" a generic type across a union? type Box<T> = { content: T }; type Boxes<string | number> = Box<string> | Box<number>; (Given that we are aware of when to use Boxes versus Box) ...

Encountering a Lint No Nested Ternary Error while utilizing the ternary operator

Is there a way to prevent the occurrence of the "no nested ternary" error in TypeScript? disablePortal options={ // eslint-disable-next-line no-nested-ternary units=== "mm&quo ...

To dismiss the Div, simply click on any area outside of it. Leveraging the power of SVG, D3

I need a way to hide my div by clicking outside of it. My SVG has a background and a graph with nodes on top of that. I have a special node (circle) on the graph, clicking on which makes a box appear. To show the box, I use the following code: d3.select ...

What are the steps to implement the `serialport` library in `deno`?

After tinkering with Deno to extract readings from an Arduino, I encountered a roadblock when it came to using the serialport library correctly. Here is what I attempted: According to a post, packages from pika.dev should work. However, when trying to use ...

What is the process for modifying the values within a BehaviorSubject<object>?

Assuming we have a BehaviorSubject<object> intelligentObject = new BehaviorSubject<object>( {property1: data1, property2: { subProperty1: info1, subProperty2: info2}, ...} ); Is there a way to modify each value and add new properti ...

Why is the Angular6 HttpClient Post method failing when Postman shows success?

Here is the code for my postmethod: postMetadata(titleParam, rankParam) { let headers = new HttpHeaders(); headers = headers.append( "Authorization", "Bearer " + this.adalService.userInfo.token ); headers = headers.append( ...