#Username from JWT only displays after site refresh

28 messages · Page 1 of 1 (latest)

mystic gyro
#

I login as user "admin" and i get a JWT response from my backend. I decode it in auth.service.ts as shown:

decodedToken() {
    const jwtHelper = new JwtHelperService();
    const token = this.getToken()!;
    console.log(jwtHelper.decodeToken(token))
    return jwtHelper.decodeToken(token);
  }

  getFullNameFromToken() {
    if (this.payload) {
      return this.payload.unique_name;
    }
  }

  getRoleFromToken() {
    if (this.payload) {
      return this.payload.role;
    }
  }

i have a user store:

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';

@Injectable({
  providedIn: 'root',
})
export class UserStoreService {
  private fullName$ = new BehaviorSubject<string>('');
  private role$ = new BehaviorSubject<string>('');

  public getRoleFromStore() {
    return this.role$.asObservable();
  }

  public setRoleForStore(role: string) {
    this.role$.next(role);
  }

  public getFullNameFromStore() {
    return this.fullName$.asObservable();
  }

  public setFullNameForStore(fullName: string) {
    this.fullName$.next(fullName);
  }

  constructor() {}
}

and my component onInit()

ngOnInit(): void {
    this.userStore.getFullNameFromStore().subscribe(val => {
      let fullNameFromToken = this.auth.getFullNameFromToken();
      this.name = val || fullNameFromToken;
    })
  }

once i log in first it doesn't display the name but after i refresh the site it displays the name.

also if I log out with my original admin user with name "admin" and log in with a second user on original load the admin user name "admin" will display but my second user name only displays after refresh

#

Username from JWT only displays after site refresh

spring briar
#

Methods that take no parameters and return Observables are better written as public member properties of the Service class:

@Injectable({ providedIn: 'root' })
export class UserStoreService {
  public readonly fullName$: Observable<string>;
  public readonly role$: Observable<string>;

  private readonly _fullNameSub$: BehaviorSubject<string>;
  private readonly _roleSub$: BehaviorSubject<string>;

  constructor() {
    this._fullNameSub$ = new BehaviorSubject<string>('');
    this._roleSub$ = new BehaviorSubject<string>();

    this.fullName$ = this._fullNameSub$.asObservable();
    this.role$ = this._roleSub$.asObservable();
  }

  public setRoleForStore(role: string): void {
    this._roleSub$.next(role);
  }

  public setFullNameForStore(fullName: string): void {
    this._fullNameSub$.next(fullName);
  }
}
#

That said, these Observables shouldn't be based on Subjects, they should be based on Observables from the authentication Service which are in turn based on Observables from HttpClient. And you shouldn't get writing your own JWT Service. Auth is hard, use a library

#

And you don't need to use OnInit except for @Input(). Initialize your properties in the constructor like how every class based language does.

#

Don't .subscribe to get values out of an Observable in Angular. Use the AsyncPipe.

mystic gyro
#

Thanks a lot. I will look into some lib's.

spring briar
#

g!auth @mystic gyro

buoyant iceBOT
#

@mystic gyro, implementing your own Authorization/Authentication solution is not advised.
Auth is a complex subject and an incorrect implementation could compromise an entire project.

An Auth solution complying with industry standards like OAuth2, OpenID, SAML, etc., requires extensive knowledge and a substantial amount of development time to implement and maintain.

Projects requiring Auth are advised to use a recognized third party Identity Provider (including, but not limited to: Auth0, AWS Cognito, Keycloak, Okta, etc.)

Many of these Identity Providers offer a free tier, which is suitable for use during development or for use in smaller projects.

spring briar
#

I would need to see your AuthService to have a better idea of what you are doing.

mystic gyro
#

here,

import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { Observable } from 'rxjs';
import { LoginRequestDto } from '../models/LoginRequestDto';
import { RegisterRequestDto } from '../models/RegisterRequestDto';
import { ResetDto } from '../models/ResetDto';
import { JwtHelperService } from '@auth0/angular-jwt';

@Injectable({
  providedIn: 'root',
})
export class AuthService {
  private baseUrl: string = 'https://localhost:7171/api/Account/';
  private payload: any;

  constructor(private http: HttpClient, private router: Router) {
    this.payload = this.decodedToken();
  }

  registerAccount(registerRequest: RegisterRequestDto) {
    return this.http.post<any>(`${this.baseUrl}register`, registerRequest);
  }

  login(loginRequest: LoginRequestDto) {
    return this.http.post<any>(`${this.baseUrl}authenticate`, loginRequest);
  }

  resetPassword(resetRequest: ResetDto) {
    return this.http.post<any>(`${this.baseUrl}reset`, resetRequest);
  }

  storeToken(tokenValue: string) {
    localStorage.setItem('token', tokenValue);
  }

  getToken() {
    return localStorage.getItem('token');
  }

  isLoggedIn(): boolean {
    return !!localStorage.getItem('token');
  }

  logout() {
    localStorage.clear();
    this.router.navigate(['login']);
  }

  decodedToken() {
    const jwtHelper = new JwtHelperService();
    const token = this.getToken()!;
    console.log(jwtHelper.decodeToken(token))
    return jwtHelper.decodeToken(token);
  }

  getFullNameFromToken() {
    if (this.payload) {
      return this.payload.unique_name;
    }
  }

  getRoleFromToken() {
    if (this.payload) {
      return this.payload.role;
    }
  }
}

spring briar
#

If you AuthService is too big to post, then I would suggest to you that each Service should do one thing well. And that generally means smaller code

mystic gyro
spring briar
#

g!any @mystic gyro Don't use any 🙂

buoyant iceBOT
#

@mystic gyro Don't use any as a type. The TS compiler effectively treats any as “please turn off type checking for this thing”. https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html#any

Always prefer to supply the proper type. You will benefit from the confidence that static typing brings, along with an enhanced developer experience through tooling (e.g. intellisense, refactoring, etc.).

In cases where you don’t know what type you want to accept, or when you want to accept anything because you will be blindly passing it through without interacting with it, you can use the unknown type. https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html#new-unknown-top-type

mystic gyro
#

❤️

spring briar
#

You don't need to store the token

mystic gyro
#

i haven't, thanks i will take a look at it and if i dont manage to fix it i will be back

south forge
#

Angular2-jwt is a library u don't need if u use auth0, it's mostly useful when you use other things, or roll your own auth.

mystic gyro
#
    const jwtHelper = new JwtHelperService();
    const token = this.getToken()!;
    console.log(jwtHelper.decodeToken(token))
    return jwtHelper.decodeToken(token);
  }```
south forge
#

I mean using Auth0 as An identity provider.

#

I would also recommend injecting the service.

mystic gyro
#

oh. im new to angular so im not familiar with these concepts😬

south forge
#

g!toh @mystic gyro