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
1 Answer
Reset to default 8I 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.