Skip to content

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 ​

  1. Google Cloud Console account
  2. Chrome extension with identity permission
  3. ExtensionLogin Pro plan or higher

Setup Steps ​

Step 1: Configure Google OAuth in Dashboard ​

  1. Go to app.extensionlogin.com
  2. Navigate to your extension's settings
  3. Click "Google OAuth" tab
  4. 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:

  1. Go to Google Cloud Console
  2. Create a new project (or select existing)
  3. Navigate to APIs & Services > Credentials
  4. Click Create Credentials > OAuth Client ID
  5. Select Chrome Extension as application type
  6. Enter your extension's ID
  7. 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: 'user@gmail.com',
  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 address
  • userinfo.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 ​

Built for Chrome Extension Developers