Firebase not logging user out - html

I took the logout function from Firebase to logout a user that logs in. I can properly log in but I clearly cannot log out. I have tested this out many times but the log out function simply does not work. Any and all help would be much appreciated. The following is my code:
export class AuthService {
private user: Observable<firebase.User>;
private userDetails: firebase.User = null;
constructor(private _firebaseAuth: AngularFireAuth, private router: Router) {
this.user = _firebaseAuth.authState;
this.user.subscribe(
(user) => {
if (user) {
this.userDetails = user;
console.log(this.userDetails);
}
else {
this.userDetails = null;
}
}
);
}
signInWithGoogle() {
return this._firebaseAuth.auth.signInWithRedirect(
new firebase.auth.GoogleAuthProvider()
)
}
signup(email: string, password: string) {
this._firebaseAuth.auth.createUserWithEmailAndPassword(email, password)
.then(value => {
console.log('Success!', value);
})
.catch(err => {
console.log('Something went wrong:',err.message);
});
}
login(email: string, password: string) {
this._firebaseAuth.auth.signInWithEmailAndPassword(email, password)
.then(value => {
console.log('Nice, it worked!');
})
.catch(err => {
console.log('Something went wrong:',err.message);
});
}
isLoggedIn() {
if (this.userDetails == null ) {
return false;
} else {
return true;
}
}
directToNext() {
if (this.isLoggedIn){
this.router.navigate(['/or-items/1']);
}
}
logout() {
this._firebaseAuth.auth.signOut()
.then((res) => this.router.navigate(['/']));
}
}
Then in the HTML:
<script>
import {AuthService} from' ./../AuthService';
function logout() {
this.authService.logout();
}
function isLoggedIn() {
this.authService.isLoggedIn();
}
</script>
<span>
<button mat-raised-button color="basic" (click)="logout()">
logout
</button>
</span>
I know that the user is not correctly being logged out because the firebase console indicates that the user is still logged in.

Qari, AFAIK the Firebase console does not indicate whether the user is logged in or not. I think what it shows is the last login date.
At least on the Android Firebase SDK, when one requests a signout, there is a callback that can be used to indicate whether the call was successful. To be doubly sure, one can get the current user info again and verify that there is no current user. You may want to try along similar lines.

Related

Login and register is not working in angular8

I am trying login and register section using reactiveform method in angular 8 but not working.I am not getting any error but when I click submit or register button getting alert message like this :[object Object]. So I can not find the solution.Login and register process not working.If anyone kown please help me to resolve this issue.
Demo:https://stackblitz.com/edit/angular-7-registration-login-example-rfqlxg?file=app%2Fweb%2F_services%2Fuser.service.ts
user.service.ts:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { User } from '../_models';
#Injectable({ providedIn: 'root' })
export class UserService {
constructor(private http: HttpClient) { }
getAll() {
return this.http.get<User[]>(`/users`);
}
getById(id: number) {
return this.http.get(`/users/` + id);
}
register(user: User) {
return this.http.post(`/users/register`, user);
}
update(user: User) {
return this.http.put(`/users/` + user.id, user);
}
delete(id: number) {
return this.http.delete(`/users/` + id);
}
}
authentication.service.ts:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { BehaviorSubject, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { User } from '../_models';
#Injectable({ providedIn: 'root' })
export class AuthenticationService {
private currentUserSubject: BehaviorSubject<User>;
public currentUser: Observable<User>;
constructor(private http: HttpClient) {
this.currentUserSubject = new BehaviorSubject<User>(JSON.parse(localStorage.getItem('currentUser')));
this.currentUser = this.currentUserSubject.asObservable();
}
public get currentUserValue(): User {
return this.currentUserSubject.value;
}
login(username: string, password: string) {
return this.http.post<any>(`/users/authenticate`, { username, password })
.pipe(map(user => {
// login successful if there's a jwt token in the response
if (user && user.token) {
// store user details and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('currentUser', JSON.stringify(user));
this.currentUserSubject.next(user);
}
return user;
}));
}
logout() {
// remove user from local storage to log user out
localStorage.removeItem('currentUser');
this.currentUserSubject.next(null);
}
}
The reason why you are seeing [object Object] is because you are passing the entire HttpErrorResponse which is an object . Your alert component template will display it properly if it is not an object.
you can change login form submit method as follows
onSubmit() {
this.submitted = true;
// stop here if form is invalid
if (this.loginForm.invalid) {
return;
}
this.loading = true;
this.authenticationService.login(this.f.username.value, this.f.password.value)
.pipe(first())
.subscribe(
data => {
this.router.navigate([this.returnUrl]);
},
error => {
this.alertService.error(error.message);
this.loading = false;
});
}
please change register components submit method as follows
onSubmit() {
this.submitted = true;
// stop here if form is invalid
if (this.loginForm.invalid) {
return;
}
this.loading = true;
this.authenticationService.login(this.f.username.value, this.f.password.value)
.pipe(first())
.subscribe(
data => {
this.router.navigate([this.returnUrl]);
},
error => {
this.alertService.error(error.message);
this.loading = false;
});
}
what i did is passed the message field from error response. if you want to have a logic for different http error codes , you can have it here and pass a message string to error method based on the error code. please try if you want to handle by error code
onSubmit() {
this.submitted = true;
// stop here if form is invalid
if (this.loginForm.invalid) {
return;
}
this.loading = true;
this.authenticationService.login(this.f.username.value, this.f.password.value)
.pipe(first())
.subscribe(
data => {
this.router.navigate([this.returnUrl]);
},
error => {
if(error.staus === 403){
this.alertService.error("You are not authorized");
}else{
this.alertService.error("Something went wrong");
}
this.loading = false;
});
}
}
if you want to display the error as it is
change the alert compoenent template as follows
<div *ngIf="message" [ngClass]="{ 'alert': message, 'alert-success': message.type === 'success', 'alert-danger': message.type === 'error' }">{{message.text |json}}</div>

Angular *ngIf updating after clicking on page or alt+tab (refocusing)

I have a strange bug on an angular project,these are the fragments of the code
#Injectable()
export class FirebaseMessagingService {
public tokenReceivedEmitter: any = new EventEmitter();
public messageReceivedEmitter: any = new EventEmitter();
constructor(
private angularFireMessaging: AngularFireMessaging) {
this.angularFireMessaging.messaging.subscribe(
(messaging) => {
messaging.onMessage = messaging.onMessage.bind(messaging);
messaging.onTokenRefresh = messaging.onTokenRefresh.bind(messaging);
}
);
}
/**
* request permission for notification from firebase cloud messaging
*
* #param userId userId
*/
requestPermission(userId) {
this.angularFireMessaging.requestToken.subscribe(
(token) => {
this.tokenReceivedEmitter.emit({status: true, result: token});
},
(err) => {
this.tokenReceivedEmitter.emit({status: false, result: err});
}
);
}
/**
* hook method when new notification received in foreground
*/
receiveMessage() {
this.angularFireMessaging.messages.subscribe(
(payload) => {
this.messageReceivedEmitter.emit(payload);
});
}
So this was the firebase messaging service which emit token receiving events and when a push notification is received.
Now in the component
ngOnInit(){
// Subscribing to firebase token receive
this.firebaseTokenSubscription = this.messagingService.tokenReceivedEmitter.subscribe(
(message) => {
if (message.status) {
const token = message.result;
this.sendNotificationToken(token);
} else {
this.snackBar.open(message.result, this.translate.instant('CLOSE')
{duration:3000});
}
}
);
}
And also I have enable/disable button in the component, here are the html parts of that code
<div *ngIf="user && !user.webPushEnabled"
class="user-verification fx-all-100 layout-all-row-wrap">
<div class="fx-gtSm-48 fx-ltMd-100 layout-all-col-nowrap">
<p>{{"EXCHANGE.PROFILE.ENABLE_DISABLE_NOTIFICATION" | translate}}</p>
</div>
<div class="fx-gtSm-48 fx-ltMd-100 offset-gtSm-4 align-all-fxEnd-fxStr">
<button mat-raised-button class="button-auth button-main-shadow"
(click)="updateNotificationStatus(true)">
{{"EXCHANGE.PROFILE.ENABLE_NOTIFICATIONS_BUTTON" | translate}}
</button>
</div>
</div>
<div *ngIf="user && user.webPushEnabled"
class="user-verification fx-all-100 layout-all-row-wrap">
<div class="fx-gtSm-48 fx-ltMd-100 layout-all-col-nowrap">
<p>{{"EXCHANGE.PROFILE.ENABLE_DISABLE_NOTIFICATION" | translate}}</p>
</div>
<div class="fx-gtSm-48 fx-ltMd-100 offset-gtSm-4 align-all-fxEnd-fxStr">
<button mat-raised-button class="del-api-key-btn button-main-shadow"
(click)="updateNotificationStatus(false)">
{{"EXCHANGE.PROFILE.DISABLE_NOTIFICATIONS_BUTTON" | translate}}
</button>
</div>
</div>
And obviously I have
updateNotificationStatus(on: boolean) {
if (on) {
this.messagingService.requestPermission(this.user.userId);
} else {
this.userService.updateNotificationStatus(null, false).subscribe(
(result) => {
this.user.webPushEnabled = false;
},
(error) => {
this.snackBar.open(error, this.translate.instant('CLOSE'), {duration: 3000});
}
);
}
}
sendNotificationToken(token) {
this.userService.updateNotificationStatus(token, true).subscribe(
(result) => {
debugger;
this.user.webPushEnabled = true;
},
(error) => {
this.snackBar.open(error, this.translate.instant('CLOSE'), {duration: 3000});
}
);
}
The problem is that when I enable push notifications it only updates html when page is reloaded or refocused(alt+tab or clicking on page with mouse). It also works fine when webpage is loaded at first time.
Pleas help any suggestions or ideas may help.
The problem was that firebase was requesting user token outside Angular's view thread, so I had to update the model in angular's view thread.
this.ngZone.run(() =>{
this.user.webPushEnabled = true;
})
It helped me out.

Angular can't read value of 'undefined' - unable to read value of 'casestudy' in the setTitle() method?

This is my component:
export class CaseStudyDetailComponent implements OnInit {
casestudy: CaseStudy;
constructor ( private caseStudyService: CaseStudyService, private route: ActivatedRoute, public titleService: Title ) { }
ngOnInit() {
this.route.params.subscribe((params: { Handle: string }) => {
this.caseStudyService.getCaseStudy(params.Handle).subscribe(casestudy => this.casestudy = casestudy);
});
this.titleService.setTitle(this.casestudy.Handle);
}
}
This is the service it is calling:
getCaseStudy(Handle: string): Observable<CaseStudy> {
return this.http.get<CaseStudy>(`${environment.apiPath}/project/handle/${Handle}`);
}
I want to be able to access the value of 'casestudy' in the 'setTitle()' method. I might potentially just be misunderstanding expected behaviour or have my syntax wrong.
Let me know if more information is required.
Because your console.log gets excecuted before your subscribe can set the response in the caseStudy.
To fix this put the console.log method in the subscribe
this.caseStudyService.getCaseStudy().subscribe(caseStudy => {
... code
console.log(caseStudy);
});

Adding a document todatabase on sign in

Since firebase does not support adding a username to a registered user by default, I try to find a way to write the username and its UserID into the database. Therefore I tried writing a username user id relation into the database. But somehow it never executes the method.
You can find the code below.
HTML template:
<mat-tab label="Register">
<div class="registerContainer">
<mat-form-field>
<input #usernameRegister (keyup.enter)="register(usernameRegister.value, emailRegister.value, passwordRegister.value)" matInput placeholder="Enter your username">
</mat-form-field>
<br>
<mat-form-field>
<input #emailRegister (keyup.enter)="register(usernameRegister.value, emailRegister.value, passwordRegister.value)" matInput placeholder="Enter your email">
</mat-form-field>
<br>
<mat-form-field>
<input #passwordRegister (keyup.enter)="register(usernameRegister.value, emailRegister.value, passwordRegister.value.toString())" matInput placeholder="Enter your password" [type]="hide ? 'text' : 'password'">
<mat-icon matSuffix (click)="hide = !hide">{{hide ? 'visibility' : 'visibility_off'}}</mat-icon>
</mat-form-field>
<br>
**<button mat-raised-button color="primary" (click)="register(usernameRegister.value, emailRegister.value, passwordRegister.value)">Register</button>**
</div>
Registration operation:
register(username:string, email: string, password: string):void{
if (username.length != 0) {
if (email.length != 0) {
this.authenticationService.register(username.toString().trim(), email.toString().trim(), password.toString())
.then((user) => {
**console.log('database operation');
this.userService.add(user, username)
.then(()=>{
console.log('wrote to database.');
})
.catch((error)=>{
console.log('Error writing to database' + error);
});**
user.sendEmailVerification()
.catch((error) => {
console.log(error);
});
this.authenticationService.logout()
.catch((error)=>{
console.log(error);
});
this.dialogRef.close();
this.snackBar.open('Registration completed', null, {duration: 1000});
})
.catch((error) => {
console.log(error);
})
}
else {
this.snackBar.open('Please enter an email address.', null, {duration: 1000});
}
}
else {
this.snackBar.open('Please enter an username.', null, {duration: 1000});
}
User model:
export class User implements IFirebaseStorable {
constructor(
public uID:string,
public username:string) {
}
}
Authentication service:
#Injectable()
export class AuthenticationService {
constructor(public afAuth: AngularFireAuth) { }
// login with email address
// returns: Promise<any>
loginWithEmail(email:string, password:string):Promise<any>{
return this.afAuth.auth.signInWithEmailAndPassword(email, password);
}
// login via facebook account
// returns: Promise<any>
loginWithFacebook():Promise<any>{
return this.afAuth.auth.signInWithPopup(new firebase.auth.FacebookAuthProvider());
}
// login via Github
// returns: Promise<any>
loginWithGithub():Promise<any>{
return this.afAuth.auth.signInWithPopup(new firebase.auth.GithubAuthProvider());
}
// login via google account
// returns: Promise<any>
loginWithGoogle():Promise<any>{
return this.afAuth.auth.signInWithPopup(new firebase.auth.GoogleAuthProvider());
}
// login via Twitter
// returns: Promise<any>
loginWithTwitter():Promise<any>{
return this.afAuth.auth.signInWithPopup(new firebase.auth.TwitterAuthProvider());
}
// register method
// parameters: Email - string, Password - string
// returns: Promise<any>
**register(username:string, email: string, password: string):Promise<any>{
return this.afAuth.auth.createUserWithEmailAndPassword(email, password);
}**
// checks whether a user is signed in or not
// returns: Boolean
userIsSignedIn():boolean{
return this.afAuth.auth.currentUser != null;
}
// logout method
// returns: Promise<any>
logout() : Promise<any> {
return this.afAuth.auth.signOut();
}
// returns: current user with following properties:
//
// displayName: string | null;
// email: string | null;
// phoneNumber: string | null;
// photoURL: string | null;
// providerId: string;
// uid: string;
getLoggedInUser():firebase.User{
return this.afAuth.auth.currentUser;
}
// send user an email to restore the password
forgotPassword(email:string):Promise<any>{
return this.afAuth.auth.sendPasswordResetEmail(email);
}
}
User database operation service
#Injectable()
export class UserService {
private userCollection: AngularFirestoreCollection<User>;
user: Observable<User[]>;
constructor(private afs: AngularFirestore) {
this.userCollection = afs.collection<User>('User');
this.user = this.userCollection.valueChanges();
}
**add(user ,username:string):Promise<DocumentReference>{
const uID = user.uid.toString();
const userAdded : User = {uID, username};
return this.userCollection.add(userAdded);
}**
}
This example is written in React through the Redux Actions, but the Javascript is all the same. You want to capture all info from the signup form, send off the signupUserWithEmailAndPassword().then set this data to the database ....
Since you're using Oauth, you will need to capture the response from every version of signin, then create your own custom Object to set into the Database. This was a PITA for me when using different Oauth Clients.
export const signupRequest = (email, password, username) => dispatch => {
// ******** The signup actions only trigger for first time users, no need to check database ********
console.log('RECIEVED USER TO SIGNUP', email, password);
firebase.auth().createUserWithEmailAndPassword(email, password)
.then((authData) => {
// ******** Firebase will create a route with whatever KEY is fed to the .set method ********
// ******** We dont actually want this to avoid deep nesting ********
// ******** So we package up our user.account object and .set(account) without any key value pairs ********
let account = {}
account.email = email.toLowerCase()
account.uid = authData.uid
account.username = username
firebase.database().ref('users/' + authData.uid).set({
account
}).then(() => {
// ******** Now we need to grap a snapshot from the DB to validate account creation and update the redux store locally ********
firebase.database().ref('users/' + authData.uid).once('value').then(function (snapshot) {
let updatedUser = snapshot.val();
console.log(' FOUND THIS USER FROM THE DB after signup', username);
}).then(() => {
dispatch(userSet(updatedUser));
})
})
}).catch((err) => console.log(err));
};

localStorage.getItem gives null while I see the item in my storage stack - Angular 4

I use localStorage to store my auth token in it.
After setting item in storage I could not fetch it again! It's while I can see the item in my browser local storage stack.
Also, when I fetch and console the item exactly after set, It's Ok and the console logs my item.
Note:
All my doing is just for user authentications and so on in an Angular 4 SPA. when I want to check my token in a component's constructor, gives me null!
Update:
Here is the code that I use:
in AuthService.ts after getting token:
localStorage.setItem('currentUser', itemData);
and it's the hole AuthService.ts
import {Injectable} from '#angular/core';
import {Http, Response} from '#angular/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';
#Injectable()
export class AuthService {
public token: string;
public userRole: number;
constructor(private http: Http) {
this.initCurrentUser();
}
initCurrentUser() {
const currentUser = JSON.parse(localStorage.getItem('currrentUser'));
this.token = currentUser && currentUser.token;
this.userRole = currentUser && currentUser.role;
}
isAuthenticated(): boolean {
return !!this.token;
}
logout(): void {
this.token = null;
this.userRole = null;
localStorage.removeItem('currentUser');
}
login(email: string, password: string): Observable<boolean> {
return this.http.post('http://localhost:8000/api/login',
{email: email, password: password})
.map((response: Response) => {
try {
let token = response.json() && response.json().token;
if (token) {
this.token = token;
let itemData= JSON.stringify({email: email, token: token});
localStorage.setItem('currentUser', itemData);
return true;
} else {
return false;
}
} catch (e) {
return false;
}
});
}
}
and finally, in HomeComponent.ts, to check authentication:
constructor(private auth: AuthService) {
auth.initCurrentUser();
console.log('Home', auth.token); // That gives me a null!
}
In every authentication check I had checked token that I had in auth service and I think that was the point.
I put the initCurrentUser() method in ngOnInit instead of constructor. and in every authentication checking I fetch the user data from local storage and process some on it to checking user authentication.
So the below is my final code that solved my problem:
ngOnInit() {
let currentUser = JSON.parse(localStorage.getItem('currrentUser'));
if (currentUser) {
this.token = currentUser.token;
this.userRole = currentUser.role;
} else {
console.log('not get on init!');
}
}
isAuthenticated(): boolean {
let data = localStorage.getItem('currentUser');
this.token = JSON.parse(data) && JSON.parse(data).token;
this.userRole = JSON.parse(data) && JSON.parse(data).role;
return !!this.token;
}
In my case, I mistakenly placed the key instead of value. Make sure you pass them in a correct order:
localStorage.setItem('key','value');