I'm trying to implement authentication with Observables in Angular 10. I'm using ReplaySubject in the AuthService for set the current user signed in. The problem is that the AuthGuard never redirect to home after user sign in. I describe the issue below on auth.guard.ts
file.
app.routing.ts
const routes: Routes = [
{
path: 'not-found',
component: NotFoundComponent,
},
{
path: '',
component: MainLayoutComponent,
children: [
{
path: '',
canActivateChild: [AuthGuard],
loadChildren: () =>
import('./modules/landing/landing.module').then(
(m) => m.LandingModule
),
},
],
},
{ path: '**', redirectTo: 'not-found', pathMatch: 'full' },
];
auth.service.ts
@Injectable({ providedIn: 'root' })
export class AuthService {
baseUrl = environment.apiUrl;
private currentUserSource = new ReplaySubject<LoggedIn>(1);
currentUser$ = this.currentUserSource.asObservable();
constructor(private http: HttpClient) {}
signIn(user: SignInDto) {
return this.http.post(this.baseUrl + 'auth/signin', user).pipe(
map((user: LoggedInDto) => {
if (user) {
localStorage.setItem('token', user.token);
this.currentUserSource.next(user);
return user;
}
})
);
}
getCurrentUser(token: string) {
if (token === null) {
this.currentUserSource.next(null);
return of(null);
}
const headers = new HttpHeaders().set('Authorization', 'Bearer ' + token);
return this.http.get(this.baseUrl + 'auth/me', { headers }).pipe(
map((user: LoggedIn) => {
if (user) {
localStorage.setItem('token', user.token);
this.currentUserSource.next(user);
}
})
);
}
}
app.component.ts
export class AppComponent implements OnInit {
constructor(private readonly authService: AuthService) {}
ngOnInit(): void {
this.getCurrentUser();
}
getCurrentUser() {
const token = localStorage.getItem('token');
this.authService.getCurrentUser(token).subscribe(() => {
console.log('user loaded');
}, console.log);
}
}
export class SignInComponent implements OnInit {
returnUrl: string;
constructor(
private readonly authService: AuthService,
private readonly router: Router,
private readonly activatedRoute: ActivatedRoute
) {}
ngOnInit(): void {
this.returnUrl = this.activatedRoute.snapshot.queryParams.returnUrl || '';
}
onSubmit() {
this.authService.signIn({username: 'xxx', password: 'xxx'}).subscribe(
(response) => {
this.router.navigateByUrl(this.returnUrl);
},
console.log
);
}
}
auth.guard.ts
The problem is here... When user sign in the currentUser$ observable is always null, everything else works fine (the token is saved in the local storage). If I try to refresh the page after sign in, the guard works fine but, if I signed in without update the page nothing happend.
@Injectable({
providedIn: 'root',
})
export class AuthGuard implements CanActivateChild {
logged: boolean = false;
constructor(private authService: AuthService, private router: Router) {}
canActivateChild(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
return this.authService.currentUser$.pipe(
map((auth) => {
// when you sign in, auth object is always null
// so the guard never redirect. But, if I refresh the page
// after the token was saved the guard works fine, the auth object comes with data
// What's the problem? :(
if (auth) {
return true;
}
this.router.navigate(['/signin'], {
queryParams: { returnUrl: state.url },
});
})
);
}
}
So the question is, what Im doing wrong or ignoring?