Skip to content

Firebase – Authentication (Code Template)

Firebase Authentication là cloud service cung cấp cho chúng ta chức năng quản lý đăng ký, đăng nhập, cũng như phân quyền rất chi là tiện lợi

So với việc tự implement thì việc sử dụng service này của Google hoàn toàn biến ứng dụng của bạn thành một con thú mà bạn chẳng cần phải động tay chân gì nhiều cả

Bài viết này sẽ chứa toàn là code dành cho ~ người nào đã biết về Firebase Authentication và muốn có resource để look up nhanh


Table of Contents

    Các phương thức Authentication

    • Email and password authentication
    • Provider integration :
      • Google
      • Apple
      • Facebook
      • Twitter
      • GitHub
    • Phone Number Auth : gửi sms kích hoạt
    • Custom Auth
    • Anonymous Auth : tạo login tạm thời

    Chức năng thường dùng

    Sign Up

    firebase.auth().createUserWithEmailAndPassword(email, password).catch(function(error) {
    
      // Handle Errors here.
      var errorCode = error.code;
      var errorMessage = error.message;
      // ...
    
    });

    Sign In

    firebase.auth().signInWithEmailAndPassword(email, password).catch(function(error) {
      // Handle Errors here.
      var errorCode = error.code;
      var errorMessage = error.message;
      // ...
    });

    Sign Out

    firebase.auth().signOut().then(function() {
      // Sign-out successful.
    }).catch(function(error) {
      // An error happened.
    });

    onStateChange

    firebase.auth().onAuthStateChanged(function(user) {
      if (user) {
        // User is signed in.
        var displayName = user.displayName;
        var email = user.email;
        var emailVerified = user.emailVerified;
        var photoURL = user.photoURL;
        var isAnonymous = user.isAnonymous;
        var uid = user.uid;
        var providerData = user.providerData;
        // ...
      } else {
        // User is signed out.
        // ...
      }
    });

    Current User

    var user = firebase.auth().currentUser;
    var name, email, photoUrl, uid, emailVerified;
    
    if (user != null) {
      name = user.displayName;
      email = user.email;
      photoUrl = user.photoURL;
      emailVerified = user.emailVerified;
      uid = user.uid;  // The user's ID, unique to the Firebase project. Do NOT use
                       // this value to authenticate with your backend server, if
                       // you have one. Use User.getToken() instead.
    }
    

    Provider Info

    var user = firebase.auth().currentUser;
    
    if (user != null) {
      user.providerData.forEach(function (profile) {
        console.log("Sign-in provider: " + profile.providerId);
        console.log("  Provider-specific UID: " + profile.uid);
        console.log("  Name: " + profile.displayName);
        console.log("  Email: " + profile.email);
        console.log("  Photo URL: " + profile.photoURL);
      });
    }

    Account Modification

    Update Profile

    var user = firebase.auth().currentUser;
    
    user.updateProfile({
      displayName: "Jane Q. User",
      photoURL: "https://example.com/jane-q-user/profile.jpg"
    }).then(function() {
      // Update successful.
    }).catch(function(error) {
      // An error happened.
    });

    Update Email

    var user = firebase.auth().currentUser;
    
    user.updateEmail("[email protected]").then(function() {
      // Update successful.
    }).catch(function(error) {
      // An error happened.
    });

    Update Password

    var user = firebase.auth().currentUser;
    var newPassword = getASecureRandomPassword();
    
    user.updatePassword(newPassword).then(function() {
      // Update successful.
    }).catch(function(error) {
      // An error happened.
    });

    Reset Password (by Send Email)

    var auth = firebase.auth();
    var emailAddress = "[email protected]";
    
    auth.sendPasswordResetEmail(emailAddress).then(function() {
      // Email sent.
    }).catch(function(error) {
      // An error happened.
    });

    Delete Account

    var user = firebase.auth().currentUser;
    
    user.delete().then(function() {
      // User deleted.
    }).catch(function(error) {
      // An error happened.
    });
    *cái này yêu cầu đăng nhập gần nhất (re-authenticate) khi thực hiện ~ chức năng như : delete acc, update email, password
    var user = firebase.auth().currentUser;
    var credential;
    
    // Prompt the user to re-provide their sign-in credentials
    
    user.reauthenticateWithCredential(credential).then(function() {
      // User re-authenticated.
    }).catch(function(error) {
      // An error happened.
    });

    Send Email Verification

    var user = firebase.auth().currentUser;
    
    user.sendEmailVerification().then(function() {
      // Email sent.
    }).catch(function(error) {
      // An error happened.
    });

    Set Language

    firebase.auth().languageCode = 'fr';
    // To apply the default browser preference instead of explicitly setting it.
    // firebase.auth().useDeviceLanguage();

    OAuth2

    Google Login

    var provider = new firebase.auth.GoogleAuthProvider();
    
    provider.addScope('https://www.googleapis.com/auth/contacts.readonly');
    
    // Optionals
    provider.setCustomParameters({
      'login_hint': '[email protected]'
    });
    
    
    // Choose 1 method below
    // pop-up
    firebase.auth().signInWithPopup(provider).then(function(result)
    
    // redirect
    firebase.auth().signInWithRedirect(provider);

    More scopes : authentication provider documentation.

    With Redirect Result

    firebase.auth().getRedirectResult().then(function(result) {
      if (result.credential) {
        // This gives you a Google Access Token. You can use it to access the Google API.
        var token = result.credential.accessToken;
      // The signed-in user info.
      var user = result.user;
    
      }
    
      // The signed-in user info.
      var user = result.user;
    }).catch(function(error) {
    
      // Handle Errors here.
      var errorCode = error.code;
      var errorMessage = error.message;
    
      // The email of the user's account used.
      var email = error.email;
    
      // The firebase.auth.AuthCredential type that was used.
      var credential = error.credential;
      // ...
    });
    

    Facebook Login

    var provider = new firebase.auth.FacebookAuthProvider();
    
    provider.addScope('user_birthday');
    
    // Optional
    provider.setCustomParameters({
      'display': 'popup'
    });

    More scopes : authentication provider documentation.

    Multi Provider

    var googleProvider = new firebase.auth.GoogleAuthProvider();
    var facebookProvider = new firebase.auth.FacebookAuthProvider();
    
    // Popup
    auth.currentUser.linkWithPopup(provider).then(function(result) {
      // Accounts successfully linked.
      var credential = result.credential;
      var user = result.user;
      // ...
    }).catch(function(error) {
      // Handle Errors here.
      // ...
    });
    
    
    // Or Redirect
    auth.currentUser.linkWithRedirect(provider)
      .then(/* ... */)
      .catch(/* ... */);
    
    // And After Redirect Result
    auth.getRedirectResult().then(function(result) {
      if (result.credential) {
        // Accounts successfully linked.
        var credential = result.credential;
        var user = result.user;
        // ...
      }
    }).catch();

    Linking Users

    Nếu sign-in success => firebase link 2 account

    Fail nếu already linked => manually handle merge

    // The implementation of how you store your user data depends on your application
    var repo = new MyUserDataRepo();
    
    // Get reference to the currently signed-in user
    var prevUser = auth.currentUser;
    
    // Get the data which you will want to merge. This should be done now
    // while the app is still signed in as this user.
    var prevUserData = repo.get(prevUser);
    
    // Delete the user's data now, we will restore it if the merge fails
    repo.delete(prevUser);
    
    
    
    
    
    // Sign in user with the account you want to link to
    auth.signInWithCredential(newCredential).then(function(result) {
      console.log("Sign In Success", result);
      var currentUser = result.user;
      var currentUserData = repo.get(currentUser);
    
      // Merge prevUser and currentUser data stored in Firebase.
      // Note: How you handle this is specific to your application
      var mergedData = repo.merge(prevUserData, currentUserData);
    
      return prevUser.linkWithCredential(result.credential)
        .then(function(linkResult) {
    
          // Sign in with the newly linked credential
          return auth.signInWithCredential(linkResult.credential);
        })
        .then(function(signInResult) {
    
          // Save the merged data to the new user
          repo.set(signInResult.user, mergedData);
        });
    }).catch(function(error) {
    
      // If there are errors we want to undo the data merge/deletion
      console.log("Sign In Error", error);
      repo.set(prevUser, prevUserData);
    });
    

    Linking

    var credential = firebase.auth.EmailAuthProvider.credential(email, password);
    
    auth.currentUser.linkWithCredential(credential)
      .then(function(usercred) {
        var user = usercred.user;
        console.log("Account linking success", user);
      }).catch(function(error) {
        console.log("Account linking error", error);
      });

    Un-link

    user.unlink(providerId).then(function() {
      // Auth provider unlinked from account
      // ...
    }).catch(function(error) {
      // An error happened
      // ...
    });

    Email Link Authentication

    Send email (có link) => Click link => auto signin & verify email

    Setup

    var actionCodeSettings = {
      // URL you want to redirect back to. The domain (www.example.com) for this
      // URL must be in the authorized domains list in the Firebase Console.
      url: 'https://www.example.com/finishSignUp?cartId=1234',
      // This must be true.
      handleCodeInApp: true,
      iOS: {
        bundleId: 'com.example.ios'
      },
      android: {
        packageName: 'com.example.android',
        installApp: true,
        minimumVersion: '12'
      },
      dynamicLinkDomain: 'example.page.link'
    };
    if handleCodeInApp: Set to true. 
    
    The sign-in operation has to always be completed in the app unlike other out of band email actions (password reset and email verifications). 
    
    This is because, at the end of the flow, the user is expected to be signed in and their Auth state persisted within the app.

    Sending

    firebase.auth().sendSignInLinkToEmail(email, actionCodeSettings)
      .then(function() {
        // The link was successfully sent. Inform the user.
        // Save the email locally so you don't need to ask the user for it again
        // if they open the link on the same device.
        window.localStorage.setItem('emailForSignIn', email);
      })
      .catch(function(error) {
        // Some error occurred, you can inspect the code: error.code
      });

    Complete

    // Confirm the link is a sign-in with email link.
    
    if (firebase.auth().isSignInWithEmailLink(window.location.href)) {
    
      // Additional state parameters can also be passed via URL.
      // This can be used to continue the user's intended action before triggering
      // the sign-in operation.
      // Get the email if available. This should be available if the user completes
      // the flow on the same device where they started it.
    
      var email = window.localStorage.getItem('emailForSignIn');
      if (!email) {
    
        // User opened the link on a different device. To prevent session fixation
        // attacks, ask the user to provide the associated email again. For example:
    
        email = window.prompt('Please provide your email for confirmation');
      }
    
      // The client SDK will parse the code from the link for you.
      firebase.auth().signInWithEmailLink(email, window.location.href)
        .then(function(result) {
    
          // Clear email from storage.
          window.localStorage.removeItem('emailForSignIn');
    
          // You can access the new user via result.user
          // Additional user info profile not available via:
          // result.additionalUserInfo.profile == null
    
          // You can check if the user is new or existing:
          // result.additionalUserInfo.isNewUser
        })
        .catch(function(error) {
    
          // Some error occurred, you can inspect the code: error.code
          // Common errors could be invalid email and invalid or expired OTPs.
        });
    }

    Cái này để tránh bị Session Fixation Attack

    1. Trước khi send email link : ta gửi kèm 1 url hiện tại
    2. Và lưu email (vd : [email protected]) vào localStorage
    3. Khi mà user mở link trong email => Check trong localStorage có email không
    4. Nếu không thì yêu cầu nhập lại đúng email info để đăng nhập

    Re-Authentication

    // Construct the email link credential from the current URL.
    var credential = firebase.auth.EmailAuthProvider.credentialWithLink(
        email, window.location.href);
    
    // Re-authenticate the user with this credential.
    firebase.auth().currentUser.reauthenticateWithCredential(credential)
      .then(function(usercred) {
    
        // The user is now successfully re-authenticated and can execute sensitive
        // operations.
      })
      .catch(function(error) {
        // Some error occurred.
      });

    Email / Password & Email Link

    // After asking the user for their email.
    var email = window.prompt('Please provide your email');
    firebase.auth().fetchSignInMethodsForEmail(email)
      .then(function(signInMethods) {
    
        // This returns the same array as fetchProvidersForEmail but for email
        // provider identified by 'password' string, signInMethods would contain 2
        // different strings:
        // 'emailLink' if the user previously signed in with an email/link
        // 'password' if the user has a password.
        // A user could have both.
    
        if (signInMethods.indexOf(
                firebase.auth.EmailAuthProvider.EMAIL_PASSWORD_SIGN_IN_METHOD) != -1) {
          // User can sign in with email/password.
        }
         if (signInMethods.indexOf(
                 firebase.auth.EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD) != -1) {
           // User can sign in with email/link.
        }
      })
      .catch(function(error) {
        // Some error occurred, you can inspect the code: error.code
      });
    }

    Phone Number Login

    Setup re-captcha

    window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('sign-in-button', {
      'size': 'invisible',
      'callback': function(response) {
        // reCAPTCHA solved, allow signInWithPhoneNumber.
        onSignInSubmit();
      }
    });
    
    
    //=======================
    window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');
    
    
    //=======================
    window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container', {
      'size': 'normal',
      'callback': function(response) {
        // reCAPTCHA solved, allow signInWithPhoneNumber.
        // ...
      },
      'expired-callback': function() {
        // Response expired. Ask user to solve reCAPTCHA again.
        // ...
      }
    });

    Action

    var phoneNumber = getPhoneNumberFromUserInput();
    var appVerifier = window.recaptchaVerifier;
    firebase.auth().signInWithPhoneNumber(phoneNumber, appVerifier)
        .then(function (confirmationResult) {
          // SMS sent. Prompt user to type the code from the message, then sign the
          // user in with confirmationResult.confirm(code).
          window.confirmationResult = confirmationResult;
        }).catch(function (error) {
          // Error; SMS not sent
          // ...
        });

    Try Again

    recaptcha.reset(window.recaptchaWidgetId);
    
    // Or, if you haven't stored the widget ID:
    window.recaptchaVerifier.render().then(function(widgetId) {
      grecaptcha.reset(widgetId);
    }

    SignIn with Code

    var code = getCodeFromUserInput();
    confirmationResult.confirm(code).then(function (result) {
      // User signed in successfully.
      var user = result.user;
      // ...
    }).catch(function (error) {
      // User couldn't sign in (bad verification code?)
      // ...
    });

    Get Credential then Login

    var credential = firebase.auth.PhoneAuthProvider.credential(confirmationResult.verificationId, code);
    
    firebase.auth().signInWithCredential(credential);

    Persistence State

    Chỉ định user_state được lưu ở đâu : javascript window, session hoặc memory

    EnumValueDescription
    firebase.auth.Auth.Persistence.LOCAL‘local’Vẫn lưu khi thoát browser. Logout để hủy
    firebase.auth.Auth.Persistence.SESSION‘session’Tab hay brower closed => Hủy
    firebase.auth.Auth.Persistence.NONE‘none’Indicates that the state will only be stored in memory and will be cleared when the window or activity is refreshed.
    firebase.auth().setPersistence(firebase.auth.Auth.Persistence.SESSION)
      .then(function() {
        // Existing and future Auth states are now persisted in the current
        // session only. Closing the window would clear any existing state even
        // if a user forgets to sign out.
        // ...
        // New sign-in will be persisted with session persistence.
        return firebase.auth().signInWithEmailAndPassword(email, password);
      })
      .catch(function(error) {
        // Handle Errors here.
        var errorCode = error.code;
        var errorMessage = error.message;
      });

    Extends Cloud Function

    exports.sendWelcomeEmail = functions.auth.user().onCreate((user) => {
      const email = user.email; // The email of the user.
      const displayName = user.displayName; // The display name of the user.
    });
    
    // or Delete
    exports.sendByeEmail = functions.auth.user().onDelete((user) => {
      // ...
    });
    Published inFirebase

    Be First to Comment

    Leave a Reply

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