DEV Community

an-object-is-a
an-object-is-a

Posted on • Updated on

Email/Password Login for Chrome Extensions

Create an Email/Password Login for Chrome Extensions using NodeJS, Express, and Javascript.


This tutorial uses a boiler-plate Google Chrome Extension setup. Learn more here.


Email/Password Login for Chrome Extensions

Let’s Begin.

We'll start by creating our REST API.
A very basic Express server with two main routes, '/login' and '/logout'.

We'll need the express package of course.

>> npm init -y
>> npm install express
Enter fullscreen mode Exit fullscreen mode

Note:
We;ve built an "authentication" middle ware function. It just simulates the act of looking up a user's credentials on a database.
We won't be creating an entire database for this lesson. Use SQL, MongoDb, whichever you like.


Let's do some web development work before we get to actual Chrome Extension work.

We'll create three pages.
A Sign In page, a Sign Out page, and a Welcome Back page. Nothing fancy.

Notice that we've attached scripts to each of our HTML pages.

Note:
A lot of this code is completely unnecessary. It's just used to make the page look nice and animate.
The only code that matters in the scripts are the 'click' listeners for the buttons.


Now that we have the Web Dev portion out of the way, let's take a look at our manifest.json.

// manifest.json
{
    "name": "basic email login system",
    "description": "testing basic email login system",
    "version": "0.1.0",
    "manifest_version": 2,
    "icons": {
        "16": "./obj-16x16.png",
        "32": "./obj-32x32.png",
        "48": "./obj-48x48.png",
        "128": "./obj-128x128.png"
    },
    "background": {
        "scripts": ["./background.js"]
    },
    "options_page": "./options.html",
    "browser_action": {
    },
    "permissions": [
        "storage",
        "http://localhost:3000/"
    ] 
}
Enter fullscreen mode Exit fullscreen mode

Note:

  1. We need to storage permission so we can store user credentials and allow for persistence.
  2. We need to put down our localhost domain so our Chrome Extension can access the REST API.

Let's do some actual Chrome Extension programming.

We'll start by coding the basic skeletal logic flow of our app.

In the popup-sign-in-script.js, when the user clicks on the button, we'll send a message to the background script asking to "login".
If we get a "success" from the background we'll change the page to the "Sign Out" page.

//...
if (email && password) {
    // send message to background script with email and password
    chrome.runtime.sendMessage({ message: 'login', 
        payload: { email,    pass }},
        function (response) {
            if (response === 'success')
            window.location.replace('./popup-sign-out.html');
        }
    });
} else {
//...
Enter fullscreen mode Exit fullscreen mode

The popup-sign-out-script.js is almost identical.

In the popup-sign-out-script.js, when the user clicks on the button, we'll send a message to the background script asking to "logout".
If we get a "success" from the background we'll change the page to the "Sign In" page.

button.addEventListener('click', () => {
    chrome.runtime.sendMessage({ message: 'logout' },
        function (response) {
            if (response === 'success')
            window.location.replace('./popup-sign-in.html');
        }
    });
});
Enter fullscreen mode Exit fullscreen mode

This file is done. You can close it.

Our popup-welcome-back-script.js click listener is identical to our "Sign Out" script's.
So we can copy and paste that logic.

button.addEventListener('click', () => {
    chrome.runtime.sendMessage({ message: 'logout' },
        function (response) {
            if (response === 'success')
            window.location.replace('./popup-sign-in.html');
        }
    });
});
Enter fullscreen mode Exit fullscreen mode

Moving to the background.js script, we create a variable to monitor the user's status and a conditional tree that catches the messages from above.

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
    if (request.message === 'login') {
        flip_user_status(true, request.payload)
            .then(res => sendResponse(res))
            .catch(err => console.log(err));

        return true;
    } else if (request.message === 'logout') {
        flip_user_status(false, null)
            .then(res => sendResponse(res))
            .catch(err => console.log(err));

        return true;
    } 
});
Enter fullscreen mode Exit fullscreen mode

Note:
We're calling a function flip_user_status(). It changes the user status to true (signed in) or false (signed out). It returns a promise that resolves into a success or fail.

Let's create that 'flip_user_status()' function.

If the user wants to sign in, we ping our '/login' route from the REST API.
If the user is permitted, we'll store their credentials on the local hard drive.

IMPORTANT: DO NOT STORE PASSWORDS IN PLAIN TEXT ANYWHERE.

For this tutorial, we won't be going into encryption.

If the user wants to sign out, we first get the user's credentials, then ping our '/logout' route from the REST API.
If the user's credentials are authenticated, then we remove those credentials from the local storage.

Before we leave the background script, let's add a function that tells us whether or not the user is signed in.

function is_user_signed_in() {
    return new Promise(resolve => {
        chrome.storage.local.get(['userStatus', 'user_info'], function (response) {
            if (chrome.runtime.lastError) resolve({ userStatus: false, user_info: {} })

            resolve(response.userStatus === undefined ?
                { userStatus: false, user_info: {} } :
                { userStatus: response.userStatus, user_info: response.user_info }
            )
        });
    });
}

// add to the 'chrome.runtime.onMessage.addListener()' routes...
} else if (request.message === 'userStatus') {
    is_user_signed_in()
        .then(res => {
            sendResponse({ message: 'success', userStatus: user_info: res.user_info.email });
        })
        .catch(err => console.log(err));
            return true;
}

chrome.browserAction.onClicked.addListener(function () {
    is_user_signed_in()
        .then(res => {
            if (res.userStatus) {
                if (return_session) {
                    chrome.windows.create({ 
                        url: './popup-welcome-back.html',
                        width: 300,
                        height: 600,
                        focused: true
                    }, function () { return_session = false });
                } else {
                    chrome.windows.create({
                        url: './popup-sign-out.html',
                        width: 300,
                        height: 600,
                        focused: true
                    });
                }
            } else {
                chrome.windows.create({
                    url: './popup-sign-in.html',
                    width: 300,
                    height: 600,
                    focused: true
                });
            }
        })
        .catch(err => console.log(err));
});
Enter fullscreen mode Exit fullscreen mode

Let's bring this all together.

Finally, in our popup-welcome-back-script.js we'll just message our background script to tell us whether or not the user is signed in.

If they are returning to a session they didn't sign out of, we'll display a welcome message for them.

chrome.runtime.sendMessage({ message: 'userStatus' },
    function (response) {
        if (response.message === 'success') {
            document.getElementById('name').innerText = 
            response.user_info;
        }
    }
});
Enter fullscreen mode Exit fullscreen mode

We're done.

Start the REST server with an node app.js and you're good to go.

sign in


If you want a more in-depth guide, check out my full video tutorial on YouTube, An Object Is A.

Create A Basic Login System for Your Google Chrome Extension

Oldest comments (0)