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: '[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 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