Angular Always Returning Undefined Or Null In Authentication System With Firebase
I'm building an authentication system with email and password
in firebase
the login and logout both work fine as response console.log(authState)
but the angular guard
always returns the method isLoggedIn()
is null
I don't know why is that?! In the constructor I have defined it with userDetails value:
Code for just the auth.service constructor:
public user: Observable<firebase.User>;
public userDetails: firebase.User = null;
constructor(
private af: AngularFireAuth,
private navCtrl: NavController,
private statusMessage: ToastMessagesService
) {
this.user = af.authState;
this.user.subscribe(
user => {
this.userDetails = user;
console.log(this.userDetails); // I get a response from this on the login page with user details ( user is logged in )
}
)
}
Code of the method alone:
isLoggedIn(): boolean {
return (this.userDetails != null) ? true : false;
}
The code of the whole service ( auth.service.ts ):
import { Injectable } from '@angular/core';
import { AngularFireAuth } from 'angularfire2/auth';
import { Observable } from 'rxjs/internal/observable';
import { NavController } from '@ionic/angular';
import { ToastMessagesService } from './toast-messages.service';
import * as firebase from 'firebase';
@Injectable({
providedIn: 'root'
})
export class AuthService {
public user: Observable<firebase.User>;
public userDetails: firebase.User = null;
constructor(
private af: AngularFireAuth,
private navCtrl: NavController,
private statusMessage: ToastMessagesService
) {
this.user = af.authState;
this.user.subscribe(
user => {
this.userDetails = user;
console.log(this.userDetails);
}
)
}
async siginInRegular(username: string, password: string) {
// const credentials = this.af.auth.email
const results = await this.af.auth.signInWithEmailAndPassword(username, password).then(
results => {
this.navCtrl.navigateForward('/home');
this.statusMessage.message(`Welcome ${results.user.email}`);
}
);
}
async register(username: string, password: string) {
try {
return await this.af.auth.createUserWithEmailAndPassword(username, password).then(
user => {
this.navCtrl.navigateForward('/profile');
this.statusMessage.message(`Welcome ${user.user.email}`);
}
);
} catch (error) {
console.dir(error);
}
}
signOut() {
return this.af.auth.signOut();
}
isLoggedIn(): boolean {
return (this.userDetails != null) ? true : false;
}
}
The code for the guard:
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from './auth.service';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(
private auth: AuthService
) {
console.log(auth.isLoggedIn());
}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
if (this.auth.isLoggedIn()) {
return true
}
console.log('Access denied!');
return false;
}
}
Answer
There could be a race in your code. this.userDetails
in your AuthService is not "ready" yet when you call it from your guard.
What you can do is, return a promise/observable in the canActivate
method, as it accepts Observable<boolean> | Promise<boolean> | boolean
.
a basic example could be this:
Add a method to get the auth state in your auth service:
get authState(): Observable<any> { return this.af.authState; }
Use it in your
canActivate()
method:canActivate(): Observable<boolean> { return this.authService.authState() .pipe( map(authState => !!authState), tap(auth => !auth ? console.log('Access Denied!') : true), take(1) ); }
Related Questions
- → How to update data attribute on Ajax complete
- → October CMS - Radio Button Ajax Click Twice in a Row Causes Content to disappear
- → Octobercms Component Unique id (Twig & Javascript)
- → Passing a JS var from AJAX response to Twig
- → Laravel {!! Form::open() !!} doesn't work within AngularJS
- → DropzoneJS & Laravel - Output form validation errors
- → Import statement and Babel
- → Uncaught TypeError: Cannot read property '__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED' of undefined
- → React-router: Passing props to children
- → ListView.DataSource looping data for React Native
- → Can't test submit handler in React component
- → React + Flux - How to avoid global variable
- → Webpack, React & Babel, not rendering DOM