This content originally appeared on DEV Community and was authored by Jay Malli
Ever dreamed of building a Chrome extension that seamlessly integrates with a user’s Google Workspace? Imagine your users, with a single click, securely logging in and unlocking a world of productivity. It sounds amazing, right?
But then, you hit a wall. A big, scary, red-bricked wall called Manifest V3.
You start seeing errors that make you want to flip your desk:
- Refused to execute inline script because it violates the following Content Security Policy…
- OAuth2 client ID is not supported…
If you’ve tried to implement Google SSO, you know the struggle. Manifest V3’s strict security policies have made old methods obsolete. So, how do you navigate this new, secure world?
Don’t worry, we’ve got the map! This guide will walk you through the modern, secure, and Google-approved way to implement G Suite SSO in your Manifest V3 extension.
Before We Dive In: A Quick Stop for Beginners
This guide jumps right into the deep end with a specific, slightly advanced topic: G Suite SSO in Manifest V3.
If you’re just starting your journey and terms like manifest.json
, service worker
, or content script
are still new to you, I highly recommend checking out my foundational guide first. It covers the A-to-Z of building your very first extension and is the perfect starting point to get you up to speed.
New to Chrome Extensions? Start with the Beginner’s Guide Here!
Once you’ve got the basics down, come on backβthis post will be waiting for you!
The Manifest V3 Challenge: Why Is It So Hard?
Google’s Manifest V3 is all about making extensions safer and more private. While this is great for users, it means:
- No More Remote Code: You can’t load scripts from external servers.
- Service Workers Only: Background tasks run in ephemeral service workers.
- Strict Content Security Policy (CSP): Inline scripts and
eval()
are forbidden.
These changes mean the old “just do a web redirect” OAuth flow is a recipe for disaster. The solution? We need to use the tool Google built specifically for this job.
The Hero of Our Story: The chrome.identity
API
Meet the chrome.identity
API. This is your magic wand for handling OAuth 2.0 within a Chrome extension. It provides a secure UI prompt, managed by Chrome itself, to handle the entire authentication flow without redirects or popups that get blocked.
Let’s build this, step-by-step.
Step 1: Get Your Extension ID & Cloud Credentials
Before you can get OAuth credentials, you need the unique ID of your extension. This is a crucial step that’s often missed, as Google needs to know exactly which extension is allowed to use your credentials.
First, Find Your Extension ID
- Make sure your extension is loaded in Chrome. If you haven’t already, go to
chrome://extensions
. - Enable Developer mode in the top right corner.
- Click Load unpacked and select your extension’s folder.
- Your extension will appear in the list with a unique ID (a long string of letters).
- Copy this ID! You’ll need it in the next part.
Next, Create OAuth Credentials
Now that you have your ID, head to the Google Cloud Platform.
- Go to the Google Cloud Console.
- Create a new project (e.g., “My Awesome Extension”).
- Navigate to APIs & Services > Credentials.
- Click + CREATE CREDENTIALS and select OAuth client ID.
- For Application type, you MUST select Chrome Extension. > Warning > This is the most common mistakeβdo not choose “Web application”!
- Give it a name (e.g., “Extension GSuite Login”).
- In the Application ID/Item ID field, paste the unique extension ID you just copied from
chrome://extensions
. - Click CREATE. You will now see your Client ID. Copy this! We’ll need it for the manifest file.
Step 2: Crafting the Perfect manifest.json
Your manifest.json
is the blueprint. It needs to declare the right permissions and your OAuth Client ID.
// filepath: manifest.json
{
"manifest_version": 3,
"name": "G Suite SSO Login Demo",
"version": "1.0",
"description": "A secure way to implement G Suite SSO with Manifest V3.",
"permissions": [
"identity",
"storage",
"alarms"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_popup": "popup.html"
},
"oauth2": {
"client_id": "YOUR_CLIENT_ID.apps.googleusercontent.com",
"scopes": [
"https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/userinfo.email"
]
},
}
Step 3: The Authentication Logic (popup.js
)
This is where the user interaction happens. A “Login” button will trigger the chrome.identity
flow.
The core function is chrome.identity.getAuthToken({ interactive: true }, ...)
. The interactive: true
flag tells Chrome it’s okay to show a user prompt if they aren’t already logged in.
function getAuthToken() {
return new Promise((resolve, reject) => {
chrome.identity.getAuthToken({ interactive: true }, function(token) {
if (chrome.runtime.lastError) {
reject(chrome.runtime.lastError);
} else {
resolve(token);
}
});
});
}
Step 4: The Service Worker (background.js
)
What about keeping the user logged in? Tokens expire! The service worker handles this gracefully in the background using the chrome.alarms
API. This is the Manifest V3-approved way to run periodic tasks like checking if an auth token needs a silent refresh.
async function refreshToken() {
try {
const result = await chrome.storage.local.get(['accessToken']);
if (result.accessToken) {
// Try to get a new token
const newToken = await new Promise((resolve, reject) => {
chrome.identity.getAuthToken({ interactive: false }, (token) => {
if (chrome.runtime.lastError) {
reject(chrome.runtime.lastError);
} else {
resolve(token);
}
});
});
if (newToken && newToken !== result.accessToken) {
await chrome.storage.local.set({ accessToken: newToken });
console.log('Token refreshed successfully');
}
}
} catch (error) {
console.error('Token refresh failed:', error);
// Clear invalid token
await chrome.storage.local.clear();
}
}
Bonus Level: Fortifying Your Extension
A working extension is great, but a secure extension is professional. Here are the essential security measures we’ve baked in to make our extension enterprise-ready.
1. The VIP List: Origin & Action Whitelisting
Your extension shouldn’t talk to just any website. Use an allowedOrigins
array to ensure only your trusted web domains can send messages. In manifest.json
, enforce this with externally_connectable
.
2. The Bouncer: Rate Limiting
To prevent DoS attacks, we allow a maximum of 10 requests per minute from any single origin. If a script goes over the limit, it gets rejected until the cooldown period is over.
3. The Principle of Least Privilege: Data Minimization
When a trusted website asks for user information, we don’t hand over the keys to the kingdom. We only provide the absolute minimum data necessary. Never send the access token to the web page.
4. The Automatic Lock: Session Management
Leaving a logged-in session active forever is a security risk. Our extension implements a 4-hour session timeout. If the user is inactive, their session data is cleared, and they will need to authenticate again.
You’ve Done It!
Congratulations! You’ve successfully navigated the Manifest V3 maze and implemented a secure, modern, and user-friendly G Suite SSO login.
By using the chrome.identity
API and layering in robust security measures, you’ve built an extension that is not only functional but also respects user privacyβthe core principle of Manifest V3.
Grab the Full Source Code
Ready to see how all the pieces fit together? The complete, production-ready code for this extension is waiting for you on GitHub.
Feel free to dive in, fork the repository, and use it as a launchpad for your own projects. Pull requests and stars are always welcome!
Let’s Connect!
If you found this guide helpful, let’s keep the conversation going! I regularly post deep dives, security tips, and new projects I’m working on.
Connect with me on LinkedInβI’d love to hear about what you’re building.
Happy coding!
This content originally appeared on DEV Community and was authored by Jay Malli