Appearance
Google OAuth
Add Google sign-in to your Chrome extension for a seamless authentication experience.
Overview
Google OAuth allows users to sign in with their existing Google account, automatically capturing their name and email without manual entry.
Prerequisites
- Google Cloud Console account
- Chrome extension with
identitypermission - ExtensionLogin Pro plan or higher
Setup Steps
Step 1: Configure Google OAuth in Dashboard
- Go to app.extensionlogin.com
- Navigate to your extension's settings
- Click "Google OAuth" tab
- Enter your Google OAuth credentials:
- Client ID: Your Google OAuth client ID
- Client Secret: Your Google OAuth client secret (stored encrypted)
Step 2: Create Google OAuth Credentials
If you don't have Google OAuth credentials yet:
- Go to Google Cloud Console
- Create a new project (or select existing)
- Navigate to APIs & Services > Credentials
- Click Create Credentials > OAuth Client ID
- Select Chrome Extension as application type
- Enter your extension's ID
- Copy the Client ID and Client Secret
Step 3: Update Extension Manifest
Add the identity permission and OAuth config to your manifest.json:
json
{
"manifest_version": 3,
"name": "Your Extension",
"version": "1.0.0",
"permissions": [
"identity",
"storage"
],
"host_permissions": [
"https://api.extensionlogin.com/*"
],
"background": {
"service_worker": "background.js",
"type": "module"
},
"oauth2": {
"client_id": "YOUR_CLIENT_ID.apps.googleusercontent.com",
"scopes": [
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile"
]
},
"key": "YOUR_EXTENSION_PUBLIC_KEY"
}Step 4: Implement Google Sign-In
javascript
import ExtensionLogin from 'extensionlogin';
// Create ExtensionLogin client
const extLogin = ExtensionLogin('el_live_xxxxxx');
// Handle Google sign-in button click
document.getElementById('google-signin').addEventListener('click', async () => {
// Use Chrome's identity API to get a Google OAuth token
chrome.identity.getAuthToken({ interactive: true }, async (token) => {
if (chrome.runtime.lastError) {
console.error('Google sign-in cancelled:', chrome.runtime.lastError.message);
return;
}
if (!token) {
console.error('No token received');
return;
}
// Fetch user info from Google
const response = await fetch('https://www.googleapis.com/oauth2/v2/userinfo', {
headers: { Authorization: `Bearer ${token}` }
});
const googleUser = await response.json();
// Identify user with ExtensionLogin
const result = await extLogin.identify({
email: googleUser.email,
name: googleUser.name,
metadata: {
googleId: googleUser.id,
picture: googleUser.picture
}
});
if (result.success) {
console.log('Google user identified:', googleUser.email);
// User data has been sent to your CRMs
} else {
console.error('Failed to identify user:', result.error);
}
});
});Complete Example
html
<!DOCTYPE html>
<html>
<head>
<title>My Extension</title>
<style>
body {
width: 320px;
padding: 20px;
font-family: system-ui, sans-serif;
}
.auth-container {
text-align: center;
}
.google-btn {
display: inline-flex;
align-items: center;
gap: 10px;
padding: 12px 24px;
background: white;
border: 1px solid #ddd;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
color: #333;
}
.google-btn:hover {
background: #f5f5f5;
}
.google-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.google-btn img {
width: 18px;
height: 18px;
}
.divider {
margin: 20px 0;
color: #666;
}
.email-form input {
width: 100%;
padding: 10px;
margin-bottom: 10px;
border: 1px solid #ddd;
border-radius: 4px;
}
.email-form button {
width: 100%;
padding: 12px;
background: #3b82f6;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.user-info {
text-align: center;
}
.user-info img {
width: 64px;
height: 64px;
border-radius: 50%;
}
.hidden {
display: none;
}
.error {
color: #dc2626;
margin-top: 10px;
font-size: 14px;
}
</style>
</head>
<body>
<div id="login-view" class="auth-container">
<h2>Welcome</h2>
<button id="google-signin" class="google-btn">
<img src="google-icon.svg" alt="Google">
Sign in with Google
</button>
<div class="divider">— or —</div>
<div class="email-form">
<input type="email" id="email" placeholder="Enter your email">
<input type="text" id="name" placeholder="Your name (optional)">
<button id="email-signin">Continue with Email</button>
</div>
<div id="error" class="error hidden"></div>
</div>
<div id="user-view" class="user-info hidden">
<img id="user-avatar" src="" alt="Avatar">
<h2 id="user-name"></h2>
<p id="user-email"></p>
<button id="logout">Sign Out</button>
</div>
<script type="module" src="popup.js"></script>
</body>
</html>javascript
import ExtensionLogin from 'extensionlogin';
// Create ExtensionLogin client
const extLogin = ExtensionLogin('el_live_xxxxxx');
// UI Elements
const loginView = document.getElementById('login-view');
const userView = document.getElementById('user-view');
const errorEl = document.getElementById('error');
// Check existing user on load
async function init() {
const user = await extLogin.getUser();
if (user) {
showUserView(user);
}
}
// Google Sign-In
document.getElementById('google-signin').addEventListener('click', async () => {
const btn = document.getElementById('google-signin');
btn.disabled = true;
btn.textContent = 'Signing in...';
hideError();
chrome.identity.getAuthToken({ interactive: true }, async (token) => {
if (chrome.runtime.lastError) {
showError(chrome.runtime.lastError.message || 'Sign-in cancelled');
resetGoogleButton();
return;
}
if (!token) {
showError('Failed to get Google token');
resetGoogleButton();
return;
}
try {
// Get user info from Google
const response = await fetch('https://www.googleapis.com/oauth2/v2/userinfo', {
headers: { Authorization: `Bearer ${token}` }
});
const googleUser = await response.json();
// Identify with ExtensionLogin
const result = await extLogin.identify({
email: googleUser.email,
name: googleUser.name,
metadata: {
googleId: googleUser.id,
picture: googleUser.picture
}
});
if (result.success) {
showUserView({
email: googleUser.email,
name: googleUser.name,
picture: googleUser.picture
});
} else {
showError(result.error || 'Failed to sign in');
}
} catch (err) {
showError('Failed to get user info from Google');
}
resetGoogleButton();
});
});
function resetGoogleButton() {
const btn = document.getElementById('google-signin');
btn.disabled = false;
btn.innerHTML = '<img src="google-icon.svg" alt="Google"> Sign in with Google';
}
// Email Sign-In
document.getElementById('email-signin').addEventListener('click', async () => {
const email = document.getElementById('email').value;
const name = document.getElementById('name').value;
if (!email) {
showError('Please enter your email');
return;
}
const result = await extLogin.identify({
email,
name: name || undefined
});
if (result.success) {
showUserView({ email, name });
} else {
showError(result.error || 'Sign-in failed');
}
});
// Logout
document.getElementById('logout').addEventListener('click', async () => {
await extLogin.logout();
// Clear Google cached token
chrome.identity.clearAllCachedAuthTokens(() => {
console.log('Google tokens cleared');
});
showLoginView();
});
// UI Helpers
function showUserView(user) {
loginView.classList.add('hidden');
userView.classList.remove('hidden');
document.getElementById('user-name').textContent = user.name || 'User';
document.getElementById('user-email').textContent = user.email;
if (user.picture) {
document.getElementById('user-avatar').src = user.picture;
} else {
const initials = (user.name || user.email).slice(0, 2).toUpperCase();
document.getElementById('user-avatar').src =
`https://ui-avatars.com/api/?name=${initials}&background=3b82f6&color=fff`;
}
}
function showLoginView() {
userView.classList.add('hidden');
loginView.classList.remove('hidden');
}
function showError(message) {
errorEl.textContent = message;
errorEl.classList.remove('hidden');
}
function hideError() {
errorEl.classList.add('hidden');
}
// Initialize
init();javascript
import ExtensionLogin from 'extensionlogin';
// Create and initialize ExtensionLogin
const extLogin = ExtensionLogin('el_live_xxxxxx');
extLogin.startBackground();
// Listen for login events
extLogin.onLogin.addListener((user) => {
console.log('[Background] User logged in:', user.email);
});
extLogin.onLogout.addListener(() => {
console.log('[Background] User logged out');
});Google OAuth Response Data
When a user signs in with Google, you can capture this data via the Google API:
javascript
// Data from Google's userinfo endpoint
{
id: '123456789012345678901', // Google ID
email: '[email protected]',
name: 'John Doe',
given_name: 'John',
family_name: 'Doe',
picture: 'https://lh3.googleusercontent.com/...',
verified_email: true
}Send this to ExtensionLogin via identify():
javascript
const result = await extLogin.identify({
email: googleUser.email,
name: googleUser.name,
metadata: {
googleId: googleUser.id,
picture: googleUser.picture,
verified: googleUser.verified_email
}
});Error Handling
Handle common Google OAuth errors:
javascript
chrome.identity.getAuthToken({ interactive: true }, async (token) => {
if (chrome.runtime.lastError) {
const error = chrome.runtime.lastError.message;
if (error.includes('canceled') || error.includes('cancelled')) {
// User closed the OAuth popup
console.log('User cancelled sign-in');
} else if (error.includes('network')) {
// Network connectivity issue
console.error('Please check your internet connection');
} else {
console.error('Sign-in error:', error);
}
return;
}
// Continue with token...
});Revoking Google Access
To fully log out and revoke Google access:
javascript
async function fullLogout() {
// Log out from ExtensionLogin
await extLogin.logout();
// Clear Chrome's cached tokens
chrome.identity.clearAllCachedAuthTokens(() => {
console.log('Cached tokens cleared');
});
// Optionally revoke the token on Google's server
chrome.identity.getAuthToken({ interactive: false }, (token) => {
if (token) {
fetch(`https://accounts.google.com/o/oauth2/revoke?token=${token}`)
.then(() => console.log('Token revoked on Google'))
.catch(console.error);
}
});
}Scopes
The default OAuth scopes request:
userinfo.email- User's email addressuserinfo.profile- User's name and profile picture
If you need additional scopes for your extension, configure them in your manifest and Google Cloud Console.
Security Notes
- Client Secret: Stored encrypted in ExtensionLogin's secure infrastructure
- Tokens: OAuth tokens are validated server-side, not stored in the extension
- HTTPS Only: All OAuth communication uses HTTPS
Troubleshooting
"OAuth not configured" Error
Ensure you've added your Google OAuth credentials in the ExtensionLogin dashboard.
"Invalid client_id" Error
Verify your client ID in manifest.json matches the one in Google Cloud Console.
Extension ID Mismatch
When testing locally, your extension ID may differ from production. Add both IDs to your Google OAuth authorized origins, or use the key field in your manifest to get a consistent ID.
"Access blocked" Error
Make sure your OAuth consent screen is configured correctly and your app is published (or your test email is added to the test users list).
Next Steps
- Chrome Extension Setup - Full setup guide
- CRM Integration - Send Google users to your CRM
- Custom Fields - Add metadata to Google users
- Security Best Practices - Keep your OAuth secure