最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Persist auth state Firebase + Chrome Extension - Stack Overflow

programmeradmin0浏览0评论

I am trying to set up authentication in my Chrome Extension. I simply want users to be able to click the extension icon, log in with email + password and then be able to use the different ponents of the extension. If the extension popup is closed, they shouldn't have to login again.

I have been scrupulously following the documentation here, here and the Chrome Extension specific documentation here with my very limited dev experience.

Here is my manifest.json.

{
  "name": "Extension",
  "version": "0.1",
  "description": "",
  "permissions": [
    "tabs",
    "activeTab",
    "storage"
  ],
  "content_security_policy": "script-src 'self' / https://*.firebaseio https://*.firebase ; object-src 'self'",
  "background": {
    "page":"background.html",
    "persistent": true
  },
  "browser_action": {
    "default_popup": "popup.html",
    "default_icon": {}
  },
  "manifest_version": 2
}

My background.html and background.js are rigorously identical to the last example I linked to above except off course I replaced the Firebase config with my own.

My popup.html is:

<!DOCTYPE html>
<html lang="en" dir="ltr">

  <head>
    <meta charset="utf-8">
    <title></title>
    <script src=".10.0/firebase.js"></script>
    <script src="firebase/initialize.js" charset="utf-8"></script>
    <script src=".5.2/firebaseui.js"></script>
    <link type="text/css" rel="stylesheet" href=".5.2/firebaseui.css"/>
    <link type="text/css" rel="stylesheet" href="styles/popup.css" />
  </head>

  <body>
    <h1>Extension</h1>
    <div id="firebaseui-auth-container"></div>
    <!-- Firebase App (the core Firebase SDK) is always required and must be listed first -->
    <script src="src/popup.js"></script>
  </body>

</html>

Where initialize.js is simply the Firebase initialization script and my popup.js is:

//Initizalier FirebaseUI instance
var ui = new firebaseui.auth.AuthUI(firebase.auth());
//Define sign-in methods
var uiConfig = {
  callbacks: {
    //Callbacl if sign up successful
    signInSuccessWithAuthResult: function(authResult) {
      // User successfully signed in.
      // Return type determines whether we continue the redirect automatically
      // or whether we leave that to developer to handle.

      //Script to replace popup content with my Extension UI

      return false;
    },
  },
  signInOptions: [
    {
      provider: firebase.auth.EmailAuthProvider.PROVIDER_ID,
      requireDisplayName: false
    }
  ],
};

//Initialize UI
ui.start('#firebaseui-auth-container', uiConfig);

Using this, I can say that login works each time I click on the extension icon, but if I close and reopen the popup, I have to login again. I have been asking about this pretty much every where I could. I also tried to ask the answer to this stackoverflow question to my background.js script but to no avail.

If I am not pletely lost, I think I have an idea of why it is this way. If I'm not mistaken, the browser action popup overrides what the background page / script are doing. However I am not sure what I should modify. I have also looked at this about authenticating Firebase with Chrome Extensions but I can't make sense of how it fits into my work.

At this point I have no idea what to do next.

I am trying to set up authentication in my Chrome Extension. I simply want users to be able to click the extension icon, log in with email + password and then be able to use the different ponents of the extension. If the extension popup is closed, they shouldn't have to login again.

I have been scrupulously following the documentation here, here and the Chrome Extension specific documentation here with my very limited dev experience.

Here is my manifest.json.

{
  "name": "Extension",
  "version": "0.1",
  "description": "",
  "permissions": [
    "tabs",
    "activeTab",
    "storage"
  ],
  "content_security_policy": "script-src 'self' https://www.gstatic./ https://*.firebaseio. https://*.firebase. https://www.googleapis.; object-src 'self'",
  "background": {
    "page":"background.html",
    "persistent": true
  },
  "browser_action": {
    "default_popup": "popup.html",
    "default_icon": {}
  },
  "manifest_version": 2
}

My background.html and background.js are rigorously identical to the last example I linked to above except off course I replaced the Firebase config with my own.

My popup.html is:

<!DOCTYPE html>
<html lang="en" dir="ltr">

  <head>
    <meta charset="utf-8">
    <title></title>
    <script src="https://www.gstatic./firebasejs/5.10.0/firebase.js"></script>
    <script src="firebase/initialize.js" charset="utf-8"></script>
    <script src="https://cdn.firebase./libs/firebaseui/3.5.2/firebaseui.js"></script>
    <link type="text/css" rel="stylesheet" href="https://cdn.firebase./libs/firebaseui/3.5.2/firebaseui.css"/>
    <link type="text/css" rel="stylesheet" href="styles/popup.css" />
  </head>

  <body>
    <h1>Extension</h1>
    <div id="firebaseui-auth-container"></div>
    <!-- Firebase App (the core Firebase SDK) is always required and must be listed first -->
    <script src="src/popup.js"></script>
  </body>

</html>

Where initialize.js is simply the Firebase initialization script and my popup.js is:

//Initizalier FirebaseUI instance
var ui = new firebaseui.auth.AuthUI(firebase.auth());
//Define sign-in methods
var uiConfig = {
  callbacks: {
    //Callbacl if sign up successful
    signInSuccessWithAuthResult: function(authResult) {
      // User successfully signed in.
      // Return type determines whether we continue the redirect automatically
      // or whether we leave that to developer to handle.

      //Script to replace popup content with my Extension UI

      return false;
    },
  },
  signInOptions: [
    {
      provider: firebase.auth.EmailAuthProvider.PROVIDER_ID,
      requireDisplayName: false
    }
  ],
};

//Initialize UI
ui.start('#firebaseui-auth-container', uiConfig);

Using this, I can say that login works each time I click on the extension icon, but if I close and reopen the popup, I have to login again. I have been asking about this pretty much every where I could. I also tried to ask the answer to this stackoverflow question to my background.js script but to no avail.

If I am not pletely lost, I think I have an idea of why it is this way. If I'm not mistaken, the browser action popup overrides what the background page / script are doing. However I am not sure what I should modify. I have also looked at this about authenticating Firebase with Chrome Extensions but I can't make sense of how it fits into my work.

At this point I have no idea what to do next.

Share Improve this question edited Apr 22, 2019 at 21:47 Experience111 asked Apr 22, 2019 at 21:41 Experience111Experience111 4184 silver badges12 bronze badges 2
  • The popup's environment exists only when it's shown. – woxxom Commented Apr 23, 2019 at 4:30
  • @wOxxOm That's what I figured but then I don't know how to use the Firebase login UI in this context. Surely there must be a way to do it, something to do with the background script maybe... I still have no idea – Experience111 Commented Apr 23, 2019 at 10:36
Add a ment  | 

1 Answer 1

Reset to default 8

I have found a solution to my problem. The answer from @cloop in the question I linked to is correct but for the sake of people that will e across this question later I will explain in my own way. I hope that it will be more beginner friendly as I am not a developer myself.

Note that this is merely my solution to have a MVP, there is very likely a better way to go about this.

First of all, do not use the Firebase UI library as this will not be patible with Chrome Extensions. I will assume that you have gone through the Chrome Extension tutorial as well as the basic of the Firebase Authentication documentation.

Now we have to discard everything we have so far and start over with an empty extension. We will set up email + password authentication for it.

First we create the manifest:

{
  "name": "Test extension",
  "version": "0.1",
  "description": "An extension to test Firebase auth",
  "permissions": [/*Insert necessary permissions*/],
  "content_security_policy": "script-src 'self' https://www.gstatic./ https://*.firebaseio. https://*.firebase. https://www.googleapis.; object-src 'self'",
  "background": {
    "page":"background.html",
    "persistent": true
  },
  "browser_action": {
    "default_popup": "popup.html",
  },
  "manifest_version": 2
}

background.html is the background page that is linked to a background.js script. This is because we have to load firebase in the <head> of the page before we can initialize it in the script, see script here for example. popup.html will be the page that we will dynamically load based on the authentication state. It is linked to a script popup.js and only contains a div element #container. We will immediatly add an event listener to that popup window to send a message to the background script using the Messaging API.

window.addEventListener('DOMContentLoaded', (_event) => {
  console.log("DOM loaded and parsed");
  //Send a message to background script informing that the page is loaded
  chrome.runtime.sendMessage({type: "popupLoad"}, function (response) {
       if (response.type == "loggedIn") {
           let htmlString = /*Your extension UI's HTML*/;
           document.querySelector("#container").innerHTML(htmlString);
       } else if (response.type == "loggedOut") {
           let htmlString = /*Log in form HTML*/
           document.querySelector("#container").innerHTML(htmlString);
       };
  });

So what we have done here is send a message to the background script as soon as the DOM of our popup.html is fully loaded to query the authentication state. The background script will send us a response object of type loggedIn or loggedOut, allowing us to decide what interface we should load for our popup.

Now we look at the background script.

First you should initialize Firebase.

var config = {
    /*Your config parameters from the Firebase console*/
  };
firebase.initializeApp(config);

Now we need to add an message listener. Note that this will listen to any message from any Chrome environement (tab, window, popup script etc) so we have to make sure we're acting on the right type of message. This is why I used {type: "popupLoad"} in the popup script message creation. All my messages have at least a type attribute.

chrome.runtime.onMessage.addListener(
    function(message, _sender, _sendResponse) {
      if (message.type == "popupLoad") {
        //Get current authentication state and tell popup
        let user = firebase.auth().currentUser;
        if (user) {
          sendResponse({type: "loggedIn"});
        } else {
          sendResponse({type: "loggedOut"});
        };
      } else if (message.type == "other") {
          //handle other types of messages
      };
    });

What we have acplished so far is that as soon as the user clicks on the extension icon, we are able to decide what the interface of the popup should be based on the authentication state. Of course if the user is logged out, they will see our log in / sign up form. The button of this form should have an event listener that sends a message (of type loginAttempt for example) to the background script, and then the background script should give a response to the popup script if the log in is successful which allows us to replace the #container content with our extension's UI. Here we see that an extension is actually a single page application.

I had to use the method firebase.auth().onAuthStateChanged() in the background script which is basically an event listener if that detects the changes in auth state if I'm not mistaken.

I won't go into further details but I hope this will be enough for beginners like me to wrap their heads around this and e up with a working prototype.

In short:

  • Don't use the Firebase UI library
  • Initialize Firebase in the background script
  • The extension is a single page application. Use the Messaging API to fetch the current authentication state or the authentication state changes from the background script to be able to decide what interface you want to serve the user

If anyone notices any issue with this answer, don't hesitate. Some credit goes to the numerous people that were kind enough to help me on dev Discord or the few developers that I emailed out of the blue and put me on the right track.

发布评论

评论列表(0)

  1. 暂无评论