OAuth 2.0 Authentication in Chrome Extensions: Complete Guide (2026)
OAuth 2.0 for Chrome Extensions
OAuth 2.0 lets your extension access Google APIs (Gmail, Drive, Calendar, Contacts) on behalf of users — without handling passwords. Chrome’s Identity API (chrome.identity) simplifies the entire OAuth flow, managing tokens and consent screens automatically.
Architecture: Why Extensions Need Special Handling
Extensions can’t use the standard OAuth redirect flow because they don’t load over HTTPS. Chrome’s Identity API provides:
- Built-in consent screen management
- Automatic token caching and refresh
- No redirect URI configuration needed
- Silent authentication for returning users
Step 1: Get a Stable Extension ID
Your OAuth credentials are tied to your extension ID, so it must stay consistent:
- Upload your extension to the Chrome Developer Dashboard (no need to publish)
- Go to Package tab → Copy the public key
- Add it to manifest.json (single line, no newlines):
{
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA..."
}- Verify your ID matches on
chrome://extensions
Step 2: Create OAuth Credentials
- Go to Google API Console
- Create or select a project
- Navigate to Credentials → Create Credentials → OAuth 2.0 Client ID
- Select Chrome Extension as application type
- Enter your extension ID
- Enable the APIs you need (e.g., People API, Gmail API, Drive API)
- Create an API key for the project
Step 3: Configure the Manifest
{
"manifest_version": 3,
"name": "My Google Integration",
"version": "1.0",
"permissions": ["identity", "storage"],
"oauth2": {
"client_id": "YOUR_CLIENT_ID.apps.googleusercontent.com",
"scopes": [
"https://www.googleapis.com/auth/contacts.readonly",
"https://www.googleapis.com/auth/userinfo.profile"
]
},
"action": {
"default_popup": "popup.html"
}
}Common OAuth Scopes
| Scope | Access |
|---|---|
userinfo.profile | Basic profile info |
userinfo.email | Email address |
contacts.readonly | Read contacts |
gmail.readonly | Read Gmail messages |
drive.readonly | Read Google Drive files |
calendar.readonly | Read calendar events |
spreadsheets.readonly | Read Google Sheets |
Step 4: Implement Authentication
Get an OAuth Token
async function getAuthToken(interactive = true) {
return new Promise((resolve, reject) => {
chrome.identity.getAuthToken({ interactive }, (token) => {
if (chrome.runtime.lastError) {
reject(new Error(chrome.runtime.lastError.message));
return;
}
resolve(token);
});
});
}Make Authenticated API Calls
async function fetchUserProfile() {
const token = await getAuthToken();
const response = await fetch(
'https://www.googleapis.com/oauth2/v2/userinfo',
{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json'
}
}
);
if (response.status === 401) {
// Token expired — remove and retry
await removeCachedToken(token);
return fetchUserProfile();
}
return response.json();
}
async function fetchContacts() {
const token = await getAuthToken();
const apiKey = 'YOUR_API_KEY';
const response = await fetch(
`https://people.googleapis.com/v1/people/me/connections?personFields=names,emailAddresses&key=${apiKey}`,
{
headers: { Authorization: `Bearer ${token}` }
}
);
return response.json();
}Token Management
async function removeCachedToken(token) {
return new Promise((resolve) => {
chrome.identity.removeCachedAuthToken({ token }, resolve);
});
}
async function signOut() {
const token = await getAuthToken(false);
if (token) {
// Revoke the token server-side
await fetch(`https://accounts.google.com/o/oauth2/revoke?token=${token}`);
await removeCachedToken(token);
}
}Complete Popup Example
// popup.js
document.getElementById('sign-in-btn').addEventListener('click', async () => {
try {
const token = await getAuthToken(true);
const profile = await fetchUserProfile();
document.getElementById('user-name').textContent = profile.name;
document.getElementById('user-email').textContent = profile.email;
document.getElementById('user-avatar').src = profile.picture;
document.getElementById('signed-out').style.display = 'none';
document.getElementById('signed-in').style.display = 'block';
} catch (error) {
document.getElementById('error').textContent = error.message;
}
});
document.getElementById('sign-out-btn').addEventListener('click', async () => {
await signOut();
document.getElementById('signed-out').style.display = 'block';
document.getElementById('signed-in').style.display = 'none';
});
// Auto-sign-in on popup open (non-interactive)
(async () => {
try {
const token = await getAuthToken(false);
if (token) {
const profile = await fetchUserProfile();
// Update UI...
}
} catch {
// Not signed in — show sign-in button
}
})();Common Pitfalls
- Mismatched extension IDs — Your unpacked ID must match the Dashboard ID. Always use the
keyfield. - Forgetting to enable APIs — Creating OAuth credentials isn’t enough. Enable each API in the Google Cloud Console.
- Scope changes after publish — Adding new scopes requires users to re-authorize. Plan your scopes upfront.
- Not handling token expiry — Tokens expire. Always handle 401 responses by clearing the cache and retrying.
- Interactive flag in service workers —
interactive: truerequires a user gesture context. Call from popup or options page.
What’s Next
OAuth 2.0 via Chrome’s Identity API gives your extension secure access to the entire Google ecosystem. Start with read-only scopes, handle token lifecycle properly, and always provide a clear sign-out option.
Grow your authenticated extension with ExtensionBooster’s developer tools.
Share this article
Build better extensions with free tools
Icon generator, MV3 converter, review exporter, and more — no signup needed.
Related Articles
Anti-Phishing Chrome Extensions in 2026: How Website Verification Actually Works (And Which Tools to Trust)
100+ fake extensions were caught phishing in 2025. How real anti-phishing extensions detect lookalike domains and which ones to trust.
I Built the Same Chrome Extension With 5 Different Frameworks. Here's What Actually Happened.
WXT vs Plasmo vs CRXJS vs Extension.js vs Bedframe. Real benchmarks, honest opinions, and the framework with 12K stars that's quietly dying.
5 Best Email Marketing Services to Grow Your Chrome Extension (2026)
Compare the top email marketing platforms for SaaS and Chrome extension developers. MailerLite, Mailchimp, Brevo, ActiveCampaign, and Drip reviewed.