0

As far as I understand I shouldn't really use async/await methods in Angular.

So I'm trying to figure out how to get it going without those methods.

I'm using canActivate function which first of all calls AuthService which asks PHP if current JWT token is valid. However, at the current moment I accomplished this only by doing so:

canActivate

async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot)
  {
    var valid_token: boolean;
    var role: number;

    await this.auth.validate_token()
    .then(res => 
    {
      valid_token = res['valid_token'],
      role = res['role']
    });

    //define if current user can access
  }

validate_token

validate_token()
  {
    return this.http.post(globals.api_url("verify-token.php"), 
      {
        jwt: localStorage.getItem('token')
      }).toPromise()
      .then(result => result)
      .catch(result => result['valid_token'] = false);
  }

And by now I have to call this validate_token() function in some other places and I don't want to set every function for async/await.

I was playing around some with observables but still wihout any proper result.

verify-token.php returns if current token is valid and some other user proporties

halfer
  • 19,824
  • 17
  • 99
  • 186
sobczi
  • 121
  • 7
  • Do you tried converting the promise to Observable? Like=> https://stackoverflow.com/questions/39319279/convert-promise-to-observable – Carlos Osiel Dec 13 '19 at 22:00
  • Why are you converting the observable (`http.post`) to an promise (`.toPromise()`) in the first place instead of returning the observable that you're looking for? – naeramarth7 Dec 13 '19 at 22:08
  • @naeramarth7 Because with observable it isn't working. ```valid_token``` is undefined. – sobczi Dec 13 '19 at 22:48
  • @CarlosOsiel Hmm... I'm feeling like this is some kind of workaround. I mean it could probably work but I want to get it working in the proper way like using only observable from the begin. – sobczi Dec 13 '19 at 22:57

2 Answers2

1

You wouldn't need to use async/await because the route guards and resolvers will wait for a promise or observable to return before it proceeds.

If all guards return true, navigation will continue. If any guard returns false, navigation will be cancelled

Your observable just needs to return a true or false value.

validate_token

validate_token()
  {
    return this.http.post(globals.api_url("verify-token.php"), 
      {
        jwt: localStorage.getItem('token')
      })
  }

canActivate

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot)
  {
    var valid_token: boolean;
    var role: number;

    return this.auth.validate_token()
      .pipe(
        tap((res) => {
          valid_token = res['valid_token'],
          role = res['role']
        }),
        map((res) => {
          return res['valid_token']
        }),
      )
  }

Notice that the observable in the canActivate guard returns res['valid_token']

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
C.OG
  • 6,236
  • 3
  • 20
  • 38
  • I changed my code to look similar to your example and still after all ```valid_token``` is undefined. Seems like code don't even entry inside of tap or map because ```console.log``` does nothing. ```valid_token``` variable after ```validate_token()``` is ```undefined```. – sobczi Dec 13 '19 at 22:42
  • 1
    sorry, just spotted a mistake .. you need to add the return keyword in the `canActivate` method. – C.OG Dec 13 '19 at 22:51
  • Yup, I did that earlier but still, it does not work. – sobczi Dec 13 '19 at 22:55
  • And maybe for you to better get my point as u wrote that I don't want to let guard to wait for promise return. Actually I want that to know if the current token was unmodified and valid. – sobczi Dec 13 '19 at 23:02
  • 1
    can you share your routing config – C.OG Dec 13 '19 at 23:03
  • 1
    Huh, I just looked at your edited code with the ```return``` state. I was returning ```var valid_token: boolean; ``` instead of ```this.auth.validate_token()```. Now it works but I have to change logic of ```verify-token.php``` because I was determining user access on canActivate class instead of .php file. No big deal after all I guess. Thank you! – sobczi Dec 13 '19 at 23:14
  • 1
    @sobczi great! can you make the answer as accepted please :) https://stackoverflow.com/help/someone-answers – C.OG Dec 13 '19 at 23:33
0

It's better to use Observable instead of Promise

private authStatusListener = new Subject<boolean>();

constructor(private http: HttpClient) { }

getAuthStatusListener() {
   return this.authStatusListener.asObservable();
}

validate_token()
{
   const user = {email: email, password: password};
   this.http.post<{token: string}>(url, user) .subscribe(response => {
        const token = response.token;
        this.authStatusListener.next(true);
   }, (error: any) => {
        this.authStatusListener.next(false);
   });
 }

and you can subscribe to the Observable from another component and for every success login will fire a true and failure login will fire a false

 this.authService.getAuthStatusListener()
  .subscribe(isAuthenticated =>{
    this.loading = isAuthenticated;
 });

You can see my simple project to understand more link

Nouh Belahcen
  • 774
  • 1
  • 11
  • 36
  • The point is I want to update this observable on every ```canActivate``` run in case of modyfing token. – sobczi Dec 13 '19 at 22:46