iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Google / Social Sign-in

Google OAuth on Firebase Auth gives one-tap sign-in with a Google account. Two modes: popup (web), redirect (web + mobile). The provider returns an ID token; everything else flows the same as email/password.

Web + mobile + scopes + linking

EXAMPLE
// 1) Web — popup
import { initializeApp } from 'firebase/app';
import {
    getAuth,
    GoogleAuthProvider,
    signInWithPopup,
    signInWithRedirect,
    getRedirectResult,
    signOut,
    onAuthStateChanged,
} from 'firebase/auth';

const app  = initializeApp(firebaseConfig);
const auth = getAuth(app);

const provider = new GoogleAuthProvider();
provider.addScope('email');
provider.addScope('profile');
provider.setCustomParameters({ prompt: 'select_account' });

async function googleLoginPopup() {
    try {
        const result = await signInWithPopup(auth, provider);
        const credential = GoogleAuthProvider.credentialFromResult(result);
        return { user: result.user, accessToken: credential.accessToken };
    } catch (e) {
        if (e.code === 'auth/popup-closed-by-user') return null;
        if (e.code === 'auth/account-exists-with-different-credential') {
            // Same email already linked to another provider
            // Surface a 'sign in with X first, then link Google' UI
            return { needLinking: e.customData.email };
        }
        throw e;
    }
}

// 2) Web — redirect (better UX on mobile browsers)
async function googleLoginRedirect() {
    await signInWithRedirect(auth, provider);     // navigates away
}

// On return to your /auth/callback page
async function handleRedirect() {
    const result = await getRedirectResult(auth);
    if (result) {
        const credential = GoogleAuthProvider.credentialFromResult(result);
        return { user: result.user, accessToken: credential.accessToken };
    }
    return null;
}

// 3) Read what came back
onAuthStateChanged(auth, (user) => {
    if (user) {
        console.log({
            uid:        user.uid,
            displayName:user.displayName,
            email:      user.email,
            verified:   user.emailVerified,    // always true from Google
            photoURL:   user.photoURL,
            providerId: user.providerData[0]?.providerId,    // 'google.com'
        });
    }
});

// 4) Get an ID token for your backend
const idToken = await auth.currentUser.getIdToken();
await fetch('/api/me', {
    method:  'POST',
    headers: { 'content-type': 'application/json', Authorization: `Bearer ${idToken}` },
});

// 5) Backend — verify the token (Admin SDK, Node)
import { getAuth as adminAuth } from 'firebase-admin/auth';

app.post('/api/me', async (req, res) => {
    const token = req.headers.authorization?.replace('Bearer ', '');
    try {
        const decoded = await adminAuth().verifyIdToken(token);
        req.uid = decoded.uid;
        // decoded.firebase.identities['google.com'] = ['<google sub>']
    } catch {
        return res.status(401).end();
    }
    res.json({ uid: req.uid });
});

// 6) Sign out
await signOut(auth);

// 7) Link Google to an existing email account
import { linkWithPopup, linkWithRedirect } from 'firebase/auth';
await linkWithPopup(auth.currentUser, provider);
// Now the user can sign in with either email/password OR Google.

// 8) Unlink
import { unlink } from 'firebase/auth';
await unlink(auth.currentUser, 'google.com');

// 9) Account-exists collision — common pattern
// User signed up with 'a@example.com' via email/password.
// Later tries Google with the same email — Firebase blocks unless emailLinkSignIn is on.
// Flow:
//   1. Detect 'auth/account-exists-with-different-credential'
//   2. Get the pending credential: GoogleAuthProvider.credentialFromError(e)
//   3. Ask user to sign in with the existing provider (email/password)
//   4. After sign-in, link the pending Google credential:
//        await linkWithCredential(auth.currentUser, pendingCred);

// 10) Additional Google scopes (Drive, Calendar, etc.)
provider.addScope('https://www.googleapis.com/auth/drive.readonly');
// After signInWithPopup, use credential.accessToken to call Google APIs
const { credential } = await signInWithPopup(auth, provider);
const token = GoogleAuthProvider.credentialFromResult(credential).accessToken;

// 11) React Native — react-native-firebase + @react-native-google-signin/google-signin
import { GoogleSignin } from '@react-native-google-signin/google-signin';
import auth from '@react-native-firebase/auth';

GoogleSignin.configure({ webClientId: 'YOUR_WEB_CLIENT_ID.apps.googleusercontent.com' });

async function googleSignIn() {
    await GoogleSignin.hasPlayServices();
    const { idToken } = await GoogleSignin.signIn();
    const credential = auth.GoogleAuthProvider.credential(idToken);
    return auth().signInWithCredential(credential);
}

// 12) iOS (native) — Firebase iOS SDK + GoogleSignIn pod
// Android — Firebase Android SDK + Google Sign-In dependency

// 13) Best practices
//   • Always require email scope — you need it to deduplicate accounts
//   • Verify ID tokens server-side; never trust client-passed uid
//   • Combine with custom claims for roles + tenant info
//   • For migrating users from another auth system, use Firebase Auth Importer
//   • For 'Sign in with Apple' — add the AppleAuthProvider (similar shape)

// 14) Hardening
//   • App Check on the client to reject bot traffic
//   • Rate limit + lock at the IP / device level for suspicious activity
//   • Email user about new device sign-ins (Firebase doesn't do this automatically)
//   • For high-risk apps, add MFA on top of Google sign-in (Firebase MFA: TOTP)
//   • Don't store the Google access token longer than you need — refresh tokens live on Firebase

Why it matters

For most apps, Google OAuth via Firebase is two API calls + one backend token verify. The piece that bites teams: same-email collision between email/password and Google — build the link flow up-front, not after a user complaint.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
import { GoogleAuthProvider, signInWithPopup } from 'firebase/auth';
const provider = new GoogleAuthProvider();
const { user } = await signInWithPopup(auth, provider);
console.log(user.displayName);
Try it Yourself »

Discussion

Loading…