Firebase Authentication with React in an MV3 Chrome Extension
Diving deep into everything you need to make Firebase Auth work with your MV3 Chrome Extension
Manifest V3 added several changes to both security policies as well as infrastructure. This can be confusing as different tools have been slow to update their documentation and still reference Manifest V2, but with the help of this post, navigating these changes should be a breeze!
🚀 To see a completed version of the code referenced here, check out with-firebase-auth.
Plasmo Framework
We will be using the Plasmo Framework in this blog post. It offers a browser extension development suite that makes creating powerful Chrome extensions seamless with live-reloading, .env
file parsing, dependencies bundling, and more.
It is free, open source, and MIT licensed.
Pre-requisites
- NPM Installed
- Package Manager (npm, yarn, pnpm, etc…)
- We use and recommend
pnpm
: https://pnpm.io/
- We use and recommend
Quickstart
Run:
1pnpm create plasmo --with-firebase-auth
The command above will give us a scaffolded project that we can immediately jump into.
Once the project is created, cd
inside and copy the example.env
file into a .env.development
file. The rest of the tutorial is all about configuring the environment variables and how to find them!
The rest of this article will be all about plumbing the needed config between Google Cloud Console and Firebase Console to facilitate authentication!
The high-level steps look like this: (Don't worry if it seems like a lot, we'll go through them in detail!)
- Create a Google Cloud Project
- Create an OAuth Consent Page
- Create an OAuth Client that uses that consent page
- Store the client ID
- Create a new Firebase project
- Links Firebase and Google Cloud Project
- Create a new Firebase app within the Firebase project
- Store your app's config
- Enable Authentication
- Enable the Google Sign-in Provider
- PROFIT!
Whew! Let's get started!
Step 1: Create a Google Cloud Project
Go to your Google Cloud Console and create a new project.
Go to your project picker.
Click on New Project.
Name it whatever you want, and click Create.
Click on Select Project to go to your project.
Step 2: Create an OAuth Consent Page
Go to the APIs & Services section of your project. This section is where we will configure our OAuth Consent Page and create our OAuth Client!
We'll need to create a consent screen. It's what users see when they're asked whether they're okay with giving your app-specific information.
Here's an example of what a consent screen looks like:
We need to go to the OAuth consent screen page to create one of these.
Select your OAuth User Type. For us, we'll be using External.
Add metadata about your consent screen.
Set your developer contact info.
Set your scopes.
Note: For Firebase projects, this isn't necessary as Firebase will set them up for you.
Add your test users.
Note: These will be the email addresses allowed to use the OAuth consent screen until Google reviews your app and approves it for broader use.
Great! Now that we've added our consent screen, it's time to create our OAuth Client!
Step 3: Create an OAuth Client that uses that consent page
Let's go to the Credentials section.
Click on Create Credentials and then OAuth Client ID. We want to create a new Client ID using that consent page we just made!
Here, we want to specify that the Client will be a Chrome app. Google has stated that they are planning to deprecate Chrome apps but don't worry, this use of Chrome App is just an artifact. It works for Chrome Extensions as well.
Now we need to specify the Application ID. This is a unique ID that every Chrome extension has. For example, LastPass's ID is hdokiejnpimakedhajhdlcegeplioahd
.
Side Quest: Demystifying Chrome Extension IDs
A Chrome Extension ID is "the first 128 bits of the SHA256 of an RSA public key encoded in base 16" (according to this Stackoverflow post). The key is PCKS8 formatted.
To read more about Chrome Extension ID and how to generate them, see: How to Create a Consistent ID for Your Chrome Extension
To quickly generate a pair of keys, use this tool: Itero KeyPairs Generator
This creates a pairs of public and private key file locally within your browser. Make sure to discard of the private key or keep it somewhere safe. As for the public key, we'll need to tell Chrome about it.
Luckily, we can specify this with a property in our package.json's manifest. Because we're using Plasmo, we don't have to tinker with a manifest.json. It gets built for us. But whenever we want to add a custom property to it, we can use the manifest
field within our package's package.json!
In this case, the property we want to add is called. Well... key
!
Also, since the key
should not be included in your production bundle, we should use Environment Variable to store this key!
Now we can take the public key value generated and put it in our .env.development
:
1CRX_PUBLIC_KEY=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArohLehlLYJbZpN+4jAqVDy9zDZrFyazMbB9xtNYtHTByqlpoHFTKkU61QKU34HAn366NtMzHu/sQwQgpMpi+V/ofK1l81OhbIufHn6
Then, reference the key in our package.json’s manifest key (this is already done for you in the scaffold):
1"manifest": { 2 "key": "$CRX_PUBLIC_KEY" 3}
Take the CRX ID - Chrome Extension's ID - from the genrator, and insert it as the Application ID in the OAuth client ID creation page:
Note: You will need to re-do the steps below when you know what your production Chrome Extension ID is (i.e., the version that gets uploaded to the Chrome Web Store)
With your client now created, you can copy that Client ID!
Step 4: Store the client ID
In the Plasmo Framework, we leverage environment variable to store and reference development keys. First, add the client ID into your .env.development
:
1PLASMO_PUBLIC_FIREBASE_CLIENT_ID=<INSERT-your-client-id>
Then, reference it in your package.json’s manifest
, under the oauth2
property (this is also already done by the scaffold):
1"oauth2": { 2 "client_id": "$PLASMO_PUBLIC_FIREBASE_CLIENT_ID", 3 "scopes": [ 4 "https://www.googleapis.com/auth/userinfo.email", 5 "https://www.googleapis.com/auth/userinfo.profile" 6 ] 7}
For production build, simply add the same key in either an .env
or .env.production
file and you are good to go, no need to fiddling with the manifest!
Step 5: Creating a New Firebase Project
We need to create a new Firebase project and link it up to our OAuth Client!
Now link your new Google Cloud project!
We need to create a new app within our new Firebase project. Click on the web button to create a new app.
Give your Firebase app a cool new name.
We'll get a code snippet that we can use in our code! Put this down somewhere for the time being. We'll reference it later!
Step 6: Store your app's config
In your .env.development
file, add your firebase credentials as follow:
1PLASMO_PUBLIC_FIREBASE_PUBLIC_API_KEY=aBunChOfRaNdOmCharaCTErsHeRE 2PLASMO_PUBLIC_FIREBASE_AUTH_DOMAIN=your-projects-name.firebaseapp.com 3PLASMO_PUBLIC_FIREBASE_PROJECT_ID=your-projects-name-1234 4PLASMO_PUBLIC_FIREBASE_STORAGE_BUCKET=your-projects-name-1234.appspot.com 5PLASMO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=123456789 6PLASMO_PUBLIC_FIREBASE_APP_ID=1:10203020:web:somethingHere1000 7PLASMO_PUBLIC_FIREBASE_MEASUREMENT_ID=G-1234567
Step 7: Set up Authentication within Firebase
Step 8: Enable Authentication
If it's your first time going to this section, you'll need to click "Get started"
Step 9: Enable the Google Sign-in Provider
Go to the Sign-in method tab, and click on Google.
Toggle enable:
Then, you will need to add your client ID (we got this from step 4 - PLASMO_PUBLIC_FIREBASE_CLIENT_ID
) into the Safelist client IDs:
Click save, then we’re done!
Step 10: Profit
Now that we have everything in place, let's test out the scaffolded project!
For the best user experience, open a terminal window and run the dev command. This will enable features like live reloading, so you don't have to refresh your extension when you make changes.
1pnpm run dev
And that's it! No need to manually do anything! The Plasmo framework will automatically build this, and you'll see your popup and newtab pages in action.
When a user's logged out, they see the following:
When they click on log in, Chrome will direct them to log in with Google.
This will use the consent screen we created a few steps ago! So if you want to modify it, you'll have to go to your Google Cloud OAuth Consent Screen section and make any modifications there.
Once the user is logged in, we can show them some info about them!
Working with Firestore
The example also demonstrates using firestore inside the newtab to read, write and observe snapshot from a single document. To test out this feature with no change to the scaffold code:
- Visit your Firestore dashboard
- Create a collection named “starships”
- Create a document called “enterprise”
- In the document, add a field named “serial”, and a value of your choosing (we recommend 1701)
- Open the newtab page, and try edit the serial number from the input - it will be synced with the firestore document!
Don’t forget to configure your firestore rules :)
Common Pitfalls
As there are many moving parts, things can go wrong. You might see these issues when you're working through this integration process. Here are some of the most common ones I've seen:
access_token audience is not for this project
- This means the OAuth Client ID you have in your manifest.json (package.json for Plasmo Framework folks) is for a Google project that isn't linked with your Firebase project. So you must've copied the wrong Client ID. Check which Google project you connected Firebase to, and use its Client ID, instead.
- If you tried the above, and you're sure that the client ID matches, it might be an issue with cached auth tokens. Go to
chrome://identity-internals
and revoke the cached token. We will add this to the Firebase example withidentity.removeCachedAuthToken
soon.
Conclusion
Congrats on making it all the way through! Adding Firebase Auth for a Chrome Extension has many moving parts, but if you follow the steps carefully and use the Plasmo Framework, you will have a fully working Firebase Auth project using React in no time!
Thanks for reading! We're Plasmo, a company on a mission to improve browser extension development for everyone. If you're a company looking to level up your browser extension, reach out, or sign up for Itero to get started.