Email/Password Login for Chrome Extensions
Tags: javascript, webdev
Published: 2020-12-03 00:43:09

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

------------
#### <center>This tutorial uses a boiler-plate Google Chrome Extension setup. Learn more [here](https://dev.to/anobjectisa/how-to-build-a-chrome-extension-4oig "here").</center>

------------

[![Email/Password Login for Chrome Extensions](https://user-images.githubusercontent.com/58220766/100158452-311ffd80-2e7a-11eb-9d9a-6f2a3076a368.png "Email/Password Login for Chrome Extensions")](https://user-images.githubusercontent.com/58220766/100158452-311ffd80-2e7a-11eb-9d9a-6f2a3076a368.png "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
```

<script src="https://gist.github.com/an-object-is-a/e6f3ee0db34607fbb93ccc7abc96dc23.js"></script>

**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.

<script src="https://gist.github.com/an-object-is-a/3aa4a0e8e2cd92b7e2da7a291674be98.js"></script>

<script src="https://gist.github.com/an-object-is-a/1dc786a262d25671d4f0be7b0c1cfc35.js"></script>

<script src="https://gist.github.com/an-object-is-a/5f78bcf047a63f1e8af5ecaa3732eede.js"></script>

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

<script src="https://gist.github.com/an-object-is-a/425486eca584b854f69aff00710e599a.js"></script>

<script src="https://gist.github.com/an-object-is-a/83708615d2d78fa331186f69be333be8.js"></script>

<script src="https://gist.github.com/an-object-is-a/9c5c32f92b824ea9a9f28f1e73adfdf5.js"></script>

**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/"
	] 
}
```

**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 {
//...
```

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');
		}
	});
});
```

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');
		}
	});
});
```

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;
	} 
});
```

**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.

<script src="https://gist.github.com/an-object-is-a/cecd6831d9e6d6f57ea1995bfe54b6c4.js"></script>

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.

<script src="https://gist.github.com/an-object-is-a/63ce07e676d4438f46ed7f473e1e41d6.js"></script>

**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));
});
```

------------

### 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;
		}
	}
});
```

**We're done.**

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

[![sign in](https://user-images.githubusercontent.com/58220766/100161664-e0130800-2e7f-11eb-82f3-e2a02ffd62e5.png "sign in")](https://user-images.githubusercontent.com/58220766/100161664-e0130800-2e7f-11eb-82f3-e2a02ffd62e5.png "sign in")

------------

#### <center>If you want a more in-depth guide, check out my full video tutorial on YouTube, **[An Object Is A](https://www.youtube.com/c/anobjectisa "An Object Is A")**.</center>

### <center>Create A Basic Login System for Your Google Chrome Extension</center>

{% youtube xU_iuZrH6Bg %}