When utilizing a Service through UserManager, the User variable may become null

Utilizing Angular 7 along with the OIDC-Client library, I have constructed an AuthService that provides access to several UserManager methods.

Interestingly, when I trigger the signInRedirectCallback function from the AuthService, the user object appears to be null.

However, if I invoke the same function using UserManager directly, the user object is not null.

For further insights, please refer to the code snippet below:

const settings : UserManagerSettings = {
  authority: 'https://localhost:5005',
  client_id: 'spa',
  redirect_uri: 'https://localhost:5001/signin',
  post_logout_redirect_uri: 'https://localhost:5001/signout',
  response_mode: 'query',
  response_type: 'code',
  scope: 'openid profile email offline_access api',
  filterProtocolClaims: true,
  loadUserInfo: true
};

@Injectable({ 
  providedIn: 'root' 
})

export class AuthService {

  private manager = new UserManager(settings);
  private user: User = null;

  constructor() {

    this.manager.getUser().then(user => {
      this.user = user;
    });

  }

  isSignedIn(): boolean {
    return this.user != null && !this.user.expired;
  }

  getClaims(): any {
    return this.user.profile;
  }

  signInRedirect(args?: any): Promise<void> {
    return this.manager.signinRedirect(args);
  }

  signInRedirectCallback(url?: string): Promise<void> {
    return this.manager.signinRedirectCallback(url).then(user => {
      this.user = user;
    });
  }

 // Other methods

}

In addition, there is an AuthenticateGuard implemented as shown below:

export class AuthenticatedGuard implements CanActivate {

  constructor(private authService: AuthService) { }

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) : boolean {

    if (this.authService.isSignedIn())
      return true;

    this.authService.signInRedirect({ state: { url: state.url }});
    return false;

  }

} 

The following component acts as the callback endpoint:

import { Component, OnInit } from '@angular/core';

import { AuthService } from '../shared/services/auth.service'
import { UserManagerSettings, UserManager } from 'oidc-client';
import { Router, ActivatedRoute } from '@angular/router';

@Component({
  selector: 'signin',
  templateUrl: './signin.component.html'
})

export class SignInComponent implements OnInit {
  private manager = new UserManager(settings);
  constructor(private authService: AuthService, private router: Router) { }

  ngOnInit() {
    this.manager.signinRedirectCallback().then(function (user) {
       console.log(user);
    });
  }
}

Unexpectedly, the user object appears as undefined when logging with console.log(user) within the callback component.

To resolve this issue, a new instance of UserManager was created in the SignInComponent instead of relying on the AuthService. Here's how it was achieved:

const settings : UserManagerSettings = {
  authority: 'https://localhost:5005',
  client_id: 'spa',
  redirect_uri: 'https://localhost:5001/signin',
  post_logout_redirect_uri: 'https://localhost:5001/signout',
  response_mode: 'query',
  response_type: 'code',
  scope: 'openid profile email offline_access api',
  filterProtocolClaims: true,
  loadUserInfo: true
};

@Component({
  selector: 'signin',
  templateUrl: './signin.component.html'
})

export class SignInComponent implements OnInit {

  private manager = new UserManager(settings);

  constructor(private router: Router) { }

  ngOnInit() {

    this.manager.signinRedirectCallback().then(function (user) {
      console.log(user);
   });

  }

}

Any thoughts on why this behavior occurs? What might be causing this discrepancy?

Thank you!

Answer №1

Here are a few suggestions to consider:

Update your response_type setting to the following:

response_type: 'id_token token'

Make sure to eliminate any instances of "null" in the user section:

private user: User;

Lastly, remove the following two elements:

response_mode

@Injectable({ 
  providedIn: 'root' 
})

Answer №2

Make sure to check these two things:

  • Firstly, don't forget to open the browser's console and review if any errors are being thrown by the signinRedirectCallback() call.
  • Secondly, take a look at the application's session storage. Is there any user data filled in by the authentication process?

Additionally, keep in mind that creating new instances of UserManager for each page isn't necessary. It's best practice to centralize all oauth logic involving oidc-client in a single service that can be injected across various pages of the application.

Answer №3

Modify the isSignedIn function to use promises.

 isSignedIn(): Promise<boolean> {
    return new Promise((resolve, reject) => {
      this.manager.getUser().then(user => {
        resolve(user != null && !user.expired);
      });
    });
  }

Update your route guard:

canActivate(): Promise<boolean> {
    return new Promise((resolve, reject) => {
      this.authService.isLoggedIn().then(result => {
        if (result) {
          resolve(result);
        } else {
          this.authService.startAuthentication().finally(() => {
            reject(false);
          });
        }
      });
    });
  }

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

Learn how to utilize a Library such as 'ngx-doc-viewer2' to preview *.docx and *.xlsx files within the application

After 3 days of searching, I finally found a solution to display my *.docx and *.xlxs files in my angular application. The API returns the files as blobs, so my task was to use that blob to show the file rather than just downloading it using window.open(bl ...

JavaScript keydown event for rotating images

I am experiencing an issue with JavaScript animation. I have incorporated code from this particular link into my keydown function. However, the code is not functioning as expected. While the code from the provided link works fine on its own, within the key ...

Solution: How to fix the error: Invalid component type, 'Draggable' cannot be used with JSX in react-draggable

I encountered an error while working on this Next.js React project Type error: 'Draggable' cannot be used as a JSX component. Its instance type 'Draggable' is not a valid JSX element. The types returned by 'render()&apo ...

Storing Firestore Timestamp as a Map in the database

Snippet Below const start = new Date(this.date + 'T' + this.time); console.log(start); // Thu Sep 12 2019 04:00:00 GMT+0200 const tournament:Tournament = { start: firebase.firestore.Timestamp.fromDate(start) } When passing the tournament ...

Manipulate elements by adding and removing classes sequentially based on an array

Previously, some had difficulty understanding my question. I have an array of variables representing the ids of 5 divs. My goal is to change the color of each div sequentially for a brief moment before reverting back, mimicking the behavior of traffic ligh ...

Guide on implementing findOne for name validation in Node.js using data from MongoDB

Can someone help solve the issue of name duplication and provide guidance on how to execute the codes in Postman API? The attached codes can be found below: *employeemodel.js enter image description here *employeecontroller.js enter image description her ...

Generating a list of items to buy using a JSON document

So here's the json file I'm working with: [ {"task":"buy bread","who":"Sarah","dueDate":"2023-10-18","done":false}, {"task":"clean car","who":"David","dueDate":"2023-08-30","done":true}, {"task":"write report","who":"Jenny","dueDate":"2023-09 ...

Finding common elements between two arrays through partial matching

Imagine I have two arrays: var array_full = ['table', 'sleeping', 'data']; var array_part = ['sleep', 'able']; My goal is to extract items from the full string array (array_full) that do not contain any e ...

Using AngularJS to send a model to ui-select

Here is the scenario at hand: A form includes a directive known as <timeZone ng-model="formModel.timeZone" This directive communicates with a web service to fetch timezone information The directive then presents the timezones in a ui-select dropdown ...

Passing "this" to the context provider value in React

While experimenting with the useContext in a class component, I decided to create a basic React (Next.js) application. The app consists of a single button that invokes a function in the context to update the state and trigger a re-render of the home compon ...

Trie-based autocomplete functionality

I am currently creating an auto-completion script and I'm considering utilizing a trie data structure. My main concern is that I want all possible matches to be returned. For instance, when I type in the letter r, I expect to see all entries beginning ...

Communication between Angular Controller and Nodejs Server for Data Exchange

Expanding on the solution provided in this thread, my goal is to implement a way to retrieve a response from the node server. Angular Controller $scope.loginUser = function() { $scope.statusMsg = 'Sending data to server...'; $http({ ...

Troubleshooting issue in Angular 6 mat-select: original array not resetting after filtering values

When filtering an array based on multiple selections from a mat-select, everything works smoothly except for one issue - if I select an option and then deselect it, the entire array disappears from the UI. However, if I select a few other options after tha ...

Some browsers are experiencing issues with Javascript functionality

My JavaScript code is functioning perfectly on my development machine in Chrome, Firefox, and Safari. However, when others test it on their browsers, the value update does not work at all. Can anyone suggest how I can replicate this issue locally? Browser ...

Combining two objects in AngularJS to create a new merged object

Is there a way to merge object1 and object2 into object3, updating values corresponding to matching keys while ignoring unmatching keys? var object1 = { "pii" : "val1", "loc" : "val2" } var object2 = { "rrb" : "val3", "voc" : "val4" } var obje ...

Choosing multiple items using ng-checked and ng-model in AngularJS

I am working with an Ionic application and encountering a minor issue, much like AngularJS. <ion-list class="list-inset subcategory" ng-repeat="item in shops"> <ion-checkbox class="item item-divider item-checkbox-right" ng-model="selectAll" ...

Production environment experiencing issues with Stripe functionality due to element remaining mounted

When making a payment in development mode, everything goes smoothly. However, when I switch to production, I encounter the following error message: v3:1 Uncaught (in promise) IntegrationError: We could not retrieve data from the specified Element. Please e ...

How to focus on an input element in Angular 2/4

Is there a way to focus on an input element using the (click) event? I'm attempting to achieve this with the following code, but it seems like there may be something missing. (I am new to Angular) sTbState: string = 'invisible'; private ele ...

Angular Kendo UI - How to Rotate X-Axis Labels in a Bar Chart

On smaller screens, I am trying to rotate x-axis labels to prevent overlapping. EXAMPLE <kendo-chart *ngIf="!yearLoader" (seriesClick)="barClick($event)"> <kendo-chart-tooltip format="{0} events"></kendo-chart-tooltip> < ...

endless refreshing material ui accordion

Facing an issue with infinite rerender while trying to create a controlled accordion component using Material UI accordion. Here is the code snippet, any insights on why this could be causing an infinite rerender? const [expanded, setExpanded] = React.us ...