0

I develop angular application and I use oauth for authentication. I install oidc-client npm packages. and all aspects work fine. but there is a bit mistake with ngoninit method. here is my code:

  ngOnInit() {
   
    this.subscription = this.authService.authNavStatus$.subscribe(status => {
      this.isAuthenticated = status;
      console.log('header'+status);
    });
  }

and what I see in console is here:

photo

As you can see on the image, oninit method called twice. first time it return false for status but the second time it return true.

for more details, my AuthService is here:

export class AuthService extends BaseService {

  // Observable navItem source
  private _authNavStatusSource = new BehaviorSubject<boolean>(false);
  // Observable navItem stream
  authNavStatus$ = this._authNavStatusSource.asObservable();

  private _loginChangedSubject = new Subject<boolean>();
  public loginChanged = this._loginChangedSubject.asObservable();

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

  constructor(private http: HttpClient, private configService: ConfigService) {
    super();

    this.manager.getUser().then(user => { 
      console.log(user);
      this.user = user;      
      this._authNavStatusSource.next(this.isAuthenticated());
    });

    // this.manager.events.addAccessTokenExpired(_ => {
    //   console.log(this.user);
    //   this._loginChangedSubject.next(false);
    // })
  }

  login() {
    return this.manager.signinRedirect();
  }

  async completeAuthentication() {
    this.user = await this.manager.signinRedirectCallback();
    this._authNavStatusSource.next(this.isAuthenticated());
  }

  async finishLogout() {
    this.user = null;
    this._loginChangedSubject.next(false);
    return this.manager.signoutRedirectCallback();
  }

  register(userRegistration: any) {
    return this.http.post(this.configService.authApiURI + '/account', userRegistration).pipe(catchError(this.handleError));
  }

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

  get authorizationHeaderValue(): string {
    return `${this.user!.token_type} ${this.user!.access_token}`;
  }

  get name(): string {
    return this.user != null ? this.user.profile.name! : '';
  }

  async signout() {
    await this.manager.signoutRedirect();
  }
}

Update:

thanks @MikeOne and @Icekson, Now The question is Why status is false at first, and it is true at second try?

Update 2: here is my header.component.html:

<pec-header [isAuth]="isAuthenticated"></pec-header>
<br>
<br>
<hr>
<h2>{{isAuthenticated}}</h2>
<hr>

and header.component.ts is here:

export class MyHeaderComponent implements OnInit {


  private destroy$: Subject<void> = new Subject<void>();
  userPictureOnly: boolean = false;
  user: any;
  isAuth: boolean;
  name: string;
  subscription: Subscription;
  isAuthenticated: boolean;



 
  constructor(private router: Router, private helpers: Helpers, private authService: AuthService) {

  }

  ngOnInit() {
   
    this.subscription = this.authService.authNavStatus$.subscribe(status => {
      this.isAuthenticated = status;
      console.log('header component => ' + status);
    });
    this.name = this.authService.name;

  }
}

the h2 tag shows 'true' value, but binded value for pec-header tag act like it is false.

thanks

pandanet
  • 53
  • 9

1 Answers1

0

ngOnInit is always triggered only once for each component. you have an Observable authStatus$ which gets emmited few times, to prevent this use rxjs operator take(1)

 ngOnInit() {
   
    this.subscription = this.authService.authNavStatus$.pipe(take(1)).subscribe(status => {
      this.isAuthenticated = status;
      console.log('header'+status);
    });
  }
icekson
  • 363
  • 1
  • 3
  • thanks for response. now the question is "why status at first is false and at second is true?". what should I do to get true result at first try? – pandanet Sep 20 '21 at 05:41
  • - you can replace BehaviorSubject with `ReplaySubject` in your AuthService `private _authNavStatusSource = new ReplaySubject(1);` OR - you can add `.pipe(filter((state) => !!state))` but notice that in this case your subscribe callback is going to handle only a true result – icekson Sep 20 '21 at 16:17
  • I added my header.component.ts and header.component.html – pandanet Sep 21 '21 at 06:29