ChrizTalk

Ionic 2 and Firebase Facebook authentication

January 26, 2017ChrizFirebase, Ionic14 comments
If you like it, please share it:

This post is based on my previous post Ionic 2 and Firebase authentication.

You can download the code on GitHub at https://github.com/henkie14/ionic2Firebase. Make sure you change the Firebase configuration in the app.module.ts file.

In this post I will continue working on the project above and add native Facebook authentication to the Ionic app.

The first thing you will have to do is to create a new Facebook App in the Facebook developer portal, install the cordova Facebook plugin and configure your Facebook app for Android and/or iOS.

There is a nice installation guide on http://ionicframework.com/docs/v2/native/facebook/.
Make sure you do the installation up to the Events chapter and you are good to go.
For future use make sure you can find the Facebook App ID and App secret you will need them in a later stage.
Facebook dashbaord app id and app secret

Eventually you should have an APP_ID, an APP_NAME and the App secret.
Now you can run the following command. (Add –save if you want the plugin and configuration to be stored in your config.xml).

$ionic plugin add cordova-plugin-facebook4 --variable APP_ID="yourAppId" --variable APP_NAME="yourAppName" --save

Let’s add a Facebook login button to the home page, open up your home.html and change it like this:

<ion-header>
  <ion-navbar>
    <ion-title>
      Ionic2Firebase
    </ion-title>
  </ion-navbar>
</ion-header>
<ion-content padding>
    <ion-title>Login</ion-title>
    <ion-row>
        <ion-item>
            <div *ngIf="auth.authState">current user is {{auth.currentUser}}</div>
        </ion-item>
    </ion-row>
    <form [formGroup]="loginForm" (ngSubmit)="submit()" novalidate>
        <ion-row>
            <ion-item>
                <ion-label for="email"></ion-label>
                <ion-input type="email" value="" placeholder="Email" formControlName="email"></ion-input>
            </ion-item>
        </ion-row>
        <ion-row>
            <ion-item>
                <ion-label for="password"></ion-label>
                <ion-input type="password" placeholder="Password" formControlName="password"></ion-input>
            </ion-item>
        </ion-row>
    </form>
    <ion-row>
        <button (click)="login()" ion-button block>Log in</button>
    </ion-row>
    <ion-row> 
        <button [navPush]="signupPage" ion-button block>Sign up</button>
    </ion-row>
    <!--new link to sign up page-->
    <ion-row> 
        <button [navPush]="resetPasswordPage" ion-button block>Reset password</button>
    </ion-row>
    <ion-row> 
        <button (click)="logout()" ion-button block>Log out</button>
    </ion-row>
    <ion-row> 
        <button (click)="loginWithFacebook()" ion-button block>Facebook login</button>
    </ion-row>
</ion-content>

And add the loginWithFacebook method to home.ts.

import { Component } from '@angular/core';
import { FormGroup, FormBuilder, Validators, AbstractControl } from '@angular/forms';
import { NavController } from 'ionic-angular';
import { AuthProvider } from '../../providers/auth-provider';
import { SignupPage } from '../signup/signup' 
import { ResetPasswordPage } from '../reset-password/reset-password'

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  loginForm: FormGroup;
  email: AbstractControl;
  password: AbstractControl;
  error: any;
  signupPage = SignupPage; 
  resetPasswordPage = ResetPasswordPage

  constructor(private navCtrl: NavController, private fb: FormBuilder, private auth: AuthProvider) {
    this.loginForm = this.fb.group({  
            'email': ['', Validators.compose([Validators.required, Validators.pattern(/[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/)])],
            'password': ['', Validators.compose([Validators.required, Validators.minLength(1)])]
        });
 
    this.email = this.loginForm.controls['email'];     
    this.password = this.loginForm.controls['password'];
  }

  loginWithFacebook(): void{
    this.auth.loginWithFacebook().subscribe((success) => {
      console.log(success);
    }, err => {
      console.log(err);
    });
  }

  login(): void { 
    if(this.loginForm.valid) {
      var credentials = ({email: this.email.value, password: this.password.value});
      this.auth.loginWithEmail(credentials).subscribe(data => {
        alert('login succeeded');
        console.log(data);
      }, error=>{
        console.log(error);
        if (error.code == 'auth/user-not-found')
        {
          alert('User not found');
        }
      });
    }
  }

  logout(): void {
    this.auth.logout();
  }
}

Last part is the implementation on the authorization provider. Change auth-provider.ts like this:

import { Injectable, EventEmitter, Inject } from '@angular/core';
import { AuthProviders, AngularFire, FirebaseAuthState, AuthMethods, FirebaseApp } from 'angularfire2'; //Add FirebaseApp
import { Observable } from "rxjs/Observable";
import { Platform } from 'ionic-angular';
import { Facebook } from 'ionic-native';
import { auth } from 'firebase'; //needed for the FacebookAuthProvider

@Injectable()
export class AuthProvider {
  private authState: FirebaseAuthState;
  public onAuth: EventEmitter<FirebaseAuthState> = new EventEmitter();
  public firebase : any;
  
  constructor(private af: AngularFire, @Inject(FirebaseApp)firebase: any,private platform: Platform) { //Add reference to native firebase SDK
    this.firebase = firebase; 
    this.af.auth.subscribe((state: FirebaseAuthState) => {
      this.authState = state;
      this.onAuth.emit(state);
    });
  }

  loginWithFacebook() {
    return Observable.create(observer => {
      if (this.platform.is('cordova')) {
        return Facebook.login(['email', 'public_profile']).then(res => {
          const facebookCredential = auth.FacebookAuthProvider.credential(res.authResponse.accessToken);
          this.firebase.auth().signInWithCredential(facebookCredential).then(()=>{
            observer.next();
          }).catch(error => {
            //console.log(error);
            observer.error(error);
          });
        });
      } else {
        return this.af.auth.login({
          provider: AuthProviders.Facebook,
          method: AuthMethods.Popup
          }).then(()=>{
            observer.next();
          }).catch(error => {
            //console.log(error);
            observer.error(error);
        });
      }
    });
  }
  
  loginWithEmail(credentials) {
    return Observable.create(observer => {
      this.af.auth.login(credentials, {
        provider: AuthProviders.Password,
        method: AuthMethods.Password
      }).then((authData) => {
        //console.log(authData);
        observer.next(authData);
      }).catch((error) => {
        observer.error(error);
      });
    });
  }

  registerUser(credentials: any) {
    return Observable.create(observer => {
      this.af.auth.createUser(credentials).then(authData => {
        //authData.auth.updateProfile({displayName: credentials.displayName, photoURL: credentials.photoUrl}); //set name and photo
        observer.next(authData);
      }).catch(error => {
        //console.log(error);
        observer.error(error);
      });
    });
  }
  
  resetPassword(emailAddress:string){
    return Observable.create(observer => {
      this.firebase.auth().sendPasswordResetEmail(emailAddress).then(function(success) {
          //console.log('email sent', success);
          observer.next(success);
        }, function(error) {
          //console.log('error sending email',error);
          observer.error(error);
        });
     });
  }

  logout() {
    this.af.auth.logout();
  }

  get currentUser():string{
    return this.authState?this.authState.auth.email:'';
  } 
}

There’s a lot going on here, let me explain.
There’s an import of Platform, that’s being used to check on what platform the app is running, based on the platform we will call the native Facebook login or a pop-up.
The Facebook import is used for calling the native Facebook plugin.
The auth import from Firebase is needed since AngularFire2 doesn’t have support for the FacebookProvider (yet).
This is why it’s important to use the correct firebase (3.3.0) and angularfire2 (2.0.0-beta.6) versions. Otherwise you might end up with a lot of ‘Duplicate identifier’ errors.

Ok, let’s run the application to see if it’s working. First test it in your browser.

$ionic serve

When you try to login by Facebook you will see the following error:

The given sign-in provider is disabled for this Firebase project. Enable it in the Firebase console, under the sign-in method tab of the Auth section.

So let’s go to the Firebase console again at https://console.firebase.google.com and select your project.
Next select Authentication on the left hand side and click the tab ‘Sign in method’.
Click Facebook and enable it. Fill in you App Id and App secret, if you didn’t already write them down you can get them from your Facebook developer portal on the dashboard page (https://developers.facebook.com).
Firebase authentication Facebook provider
Make sure you copy the OAuth redirect URI and click the save button.

Now you should go back to the Facebook developer portal and click ‘+ add product’ on the lef hand side and select ‘Facebook Login’.
Facebook login product dashboard

Next click ‘settings’ below Facebook Login on the left hand side and fill in the Auth redirect URI you’ve copied from the Firebase Facebook provider settings.
Facebook Login client oauth settings

Let’s test it again in your browser.

$ionic serve

When you click the Facebook login button you should see a popup where you can connect with your Facebook account and when you login, it should show the corresponding email address as the current user.
You can also check the users tab on the authentication menu in the Firebase console to see all registered users and their provider.

Now let’s try it on android to see if the native Facebook functionality is working. Connect you Android phone and run the following commands.

$ionic platform add android
$ionic run android

Okay, when trying to login by Facebook you will see a native popup, but with this message: “Facebook test error in development mode.”
This can be fixed by going to the Facebook developer portal again and after selecting your project, you should select ‘App Review’ from the menu on the left and make the app public.
Facebook app development mode

This should be all!

If things don’t seem to work or you see the following Firebase error: auth/network-request-failed. Try this:

$ionic platform rm android
$ionic platform add android

You can try it out on iOS by connecting you iOS device and run:

$ionic platform add ios
$ionic run ios

Please leave a message if you got it working or not or things aren’t clear or whatever 🙂

Next is native Google login…


If you like it, please share it:
Previous Post Ionic 2 and Firebase authentication Next Post Ionic 2 and Firebase Google authentication

14 comments. Leave new

Osiris
February 2, 2017 2:57 am

Your tutorial really helped me, thanks a lot. Hope you keep doing this.

Reply
Alice
March 29, 2017 5:11 pm

Hey Chriz!
I’ve been following your tutorials, they’re so helpful. I manged to get the authentication with email and Firebase working fine but I’m having some issues with Facebook.
In the browser when I click the login to Facebook button it opens up a new balk popup window(as if it were about to ask for authentication) but then the window closes.
Console logs give back two errors I just can’t seem to fix:
1. Uncaught DOMException: Blocked a frame with origin “https://*my-app-name*.firebaseapp.com” from accessing a cross-origin frame.
at :1:15

2. POST https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyAssertion?key=*my-firebase-key* 400 ()
login.ts:40 R {code: “auth/internal-error”, message: “https://*myapp.firebaseapp.com/__/auth/handler”}

The second one seems like something wrong with my firebase side of things but I’ve made sure of all the config on the Facebook side and it is all enabled on Firebase side also!

I’m also using the versions of angular fire and firebase you specified. I’ve been really stuck on this issue so any ideas at all would be greatly appreciated!!!!

Thanks for the tutorial!
Alice

Reply
Chriz
March 29, 2017 10:17 pm

Hi Alice,
It’s hard to help without being able to reproduce the error…
Could you try to get some more information from the error message. (Add some extra console logging in the error handlers)
It might be something like this:
https://github.com/firebase/firebaseui-web/issues/10
or this:
https://groups.google.com/forum/#!topic/firebase-talk/eVvL2j4UWL4
Hope this helps.

Reply
Almog
July 11, 2017 12:59 pm

Alice are you solve the problem ? i have too this issue

Reply
Andy
April 6, 2017 8:16 pm

how do I PhotoURL to view photo. Can you give an example
html
current user PhotoURI: {{auth.currentUserPhotoURI}}
and
ts
get currentUserPhotoURI():string{
return this.authState?this.authState.auth.photoURL:”;
}
Thanks

Reply
Chriz
April 10, 2017 2:49 pm

html should be something like this:

Reply
Steve
April 11, 2017 10:37 pm

Hey,

i tried your tutorial and it works great! Thanks for that.
But at the moment im struggeling at the point to

1. Check if the User is already Loggedin on the Homepage
2. Redirect him if he is already logged in or if he log himself in.

I tried with the currentUser function but it doesnt work.

Would be amazing if you could help me with that

Reply
Chriz
April 12, 2017 10:44 am

Hi Steve,
There is an onAuth event on the AuthProvider. You can subscribe to it and see if the user is authenticated. Something like this:

auth.onAuth.subscribe((authState)=>{
if (authState){
console.log('Logged in user :', authState.auth.email);
}
});

In the app.component.ts file you can see it’s already implemented.
You only have to redirect to another page (set the rootPage to your homepage).

Reply
adir zoari
July 19, 2017 6:02 pm

how do I make this in ionic 3 after they update angularfire2?
they way you did not works.

Reply
adir zoari
July 19, 2017 6:04 pm

hello, can you please update the tutorial? how can I do that in ionic 3 after firebase update to latest angularfire?
I tried your way and it’s not working.

Reply
Jadson
August 22, 2017 9:06 pm

I’m getting the following error in response to the method: firebase.auth().signInWithCredential
Error: 400
POST https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyAssertion?key=AIzaSyDTzFkA0rhc8DH53I6iwVD_4ptAqYbPsTQ 400 ()

16:59:31.051 ion-dev.js?v=2.1.3:156 {“error”:{“errors”:[{“domain”:”global”,”reason”:”invalid”,”message”:”Unsuccessful debug_token response from Facebook: {\”error\”:{\”message\”:\”(#100) The App_id in the input_token did not match the Viewing App\”,\”type\”:\”OAuthException\”,\”code\”:100,\”fbtrace_id\”:\”BuFBiZERFu2\”}}”}],”code”:400,”message”:”Unsuccessful debug_token response from Facebook: {\”error\”:{\”message\”:\”(#100) The App_id in the input_token did not match the Viewing App\”,\”type\”:\”OAuthException\”,\”code\”:100,\”fbtrace_id\”:\”BuFBiZERFu2\”}}”}}

Reply
Simerjit
October 10, 2017 11:52 am

Are you able to manage this issue?? I am facing the same issue

Reply
Chriz
October 13, 2017 4:02 pm

Just tested it and it all works, are you sure you are using the correct Facebook App_Id and App_name?

Reply
Jadson
October 14, 2017 3:56 am

In APP settings on Facebook in URL Site http://localhost/

Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Recent Posts

  • Ionic 3 and Firebase Facebook authentication using AngularFire2
  • Ionic 3 and Firebase authentication using AngularFire2
  • Ionic 3, Firebase and AngularFire2
  • Ionic 2 and Font Awesome using Sass
  • Using Google Fonts in Ionic 2

My Ionic 2 Theme

Please have a look at my new Ionic 2 theme.

&copy 2016 ChrizTalk