1

I'm building a simple login page with authentication using Angular and Express. I have the following:

  • a login component
  • a service that makes http calls and sets the local storage with the received jwt token
  • a route guard for registration page

My guard is working in that it prevents access to the '/registration' route if there is no token. Because the very first login does not have a token, and the guard seems to check before the token is set when the login component's onSubmit() is invoked, I have to trigger onSubmit() twice - once to get the key and then another to login. I'd like to be able to login immediately after entering the correct credentials.

How do I resolve this? Thanks in advance!

login-component.ts

...
this.loginForm = this.fb.group({
    username: ['', Validators.required],
    password: ['', Validators.required]
})
...
onSubmit() {
    const formValue = this.loginForm.value;
    if (formValue.username && formValue.password) {
      this.authService.login(formValue.username, formValue.password)
        .subscribe(
          resp => { console.log(resp); },
          err => { console.log(err); }
        )
      this.router.navigateByUrl('/registration');
    }
  }

auth-service.service.ts:

export class AuthSerivce {

constructor(private http: HttpClient) {}

login(username: string, password: string) {
const body = {
  username: username,
  password: password
}
return this.http.post<AuthResp>(ROUTES.login, body)
  .pipe(
    tap(res => this.setSession(res)),
    catchError(this.handleError),
    shareReplay()
  )
}

...

private setSession(authResp: AuthResp) {
    const expiresAt = moment().add(authResp.expiresIn, 'second');

    localStorage.setItem('id_token', authResp.token);
    localStorage.setItem("expires_at", JSON.stringify(expiresAt.valueOf()));
}


public isLoggedIn() {
    return moment().isBefore(this.getExpiration());
}

public getExpiration() {
    const expiration = localStorage.getItem("expires_at");
    const expiresAt = JSON.parse(expiration);
    return moment(expiresAt); 
}
}

auth.guard.ts

export class AuthGuard implements CanActivate {
    constructor(
        private _authService: AuthService,
        private _router: Router) { }


canActivate(): boolean {
    if (this._authService.isLoggedIn()) {
        return true;
    } else {
        this._router.navigate(['login']);
        return false;
    }
  }
}
Jacob L
  • 133
  • 2
  • 18

1 Answers1

0

Resolved the issue. I needed to place my navigation in the subscription of my login call:

login-component.ts

...
this.loginForm = this.fb.group({
    username: ['', Validators.required],
    password: ['', Validators.required]
})
...
onSubmit() {
    const formValue = this.loginForm.value;
    if (formValue.username && formValue.password) {
      this.authService.login(formValue.username, formValue.password)
        .subscribe(
          resp => { 
              console.log(resp);
              this.router.navigateByUrl('/registration'); 
          },
          err => { console.log(err); }
        )
    }
  }
Jacob L
  • 133
  • 2
  • 18