Skip to main content

Command Palette

Search for a command to run...

Google OAuth Authentication with React, Node.js, and Express

Updated
5 min readView as Markdown
Google OAuth Authentication with React, Node.js, and Express
A

Hi there! I'm Aditya, a passionate Full-Stack Developer driven by a love for turning concepts into captivating digital experiences. With a blend of creativity and technical expertise, I specialize in crafting user-friendly websites and applications that leave a lasting impression. Let's connect and bring your digital vision to life!

Google Sign-In is one of the easiest ways to authenticate users without asking them to create and remember another password. In this guide, you'll learn how to integrate Google OAuth into a React application using @react-oauth/google and verify users securely on a Node.js backend.

By the end of this guide, you'll have:

  • A React frontend with Google Sign-In
  • A Node.js backend that verifies Google ID tokens
  • JWT-based authentication
  • Automatic user creation for first-time sign-ins

Prerequisites

Before getting started, make sure you have:

Requirement Description
Node.js Installed on your machine
React Vite or Create React App
Express Backend server
MongoDB Database for storing users
Google Cloud Account Required to create OAuth credentials

Create Google OAuth Credentials

Open the Google Cloud Console and navigate to the Credentials page.

Create a new OAuth Client ID with the following settings.

Option Value
Credential Type OAuth Client ID
Application Type Web Application

After creating the credentials, copy the generated Client ID. You'll use it in both the frontend and backend.


Frontend Setup

Install Required Package

npm install @react-oauth/google

Configure Environment Variables

Create a .env file in your frontend project.

VITE_GOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.com
VITE_BACKEND_URL=http://localhost:5000

Wrap Your Application

Update your main.tsx file.

import { GoogleOAuthProvider } from "@react-oauth/google";

const clientId = import.meta.env.VITE_GOOGLE_CLIENT_ID;

<GoogleOAuthProvider clientId={clientId}>
  <App />
</GoogleOAuthProvider>;

This provider makes the Google authentication context available throughout your application.


Create the Google Authentication Component

Create a new component called GoogleAuth.tsx.

import { GoogleLogin } from "@react-oauth/google";
import axios from "axios";

const GoogleAuth = () => {
  const handleSuccess = async (credentialResponse) => {
    try {
      const res = await axios.post(
        `${import.meta.env.VITE_BACKEND_URL}/api/v1/google-signin`,
        {
          credential: credentialResponse.credential,
        }
      );

      localStorage.setItem("token", res.data.token);
      alert("Login successful");
    } catch (err) {
      console.error("Login error:", err);
      alert("Login failed");
    }
  };

  return (
    <GoogleLogin
      onSuccess={handleSuccess}
      onError={() => alert("Google Login Failed")}
    />
  );
};

export default GoogleAuth;

Once the user signs in successfully, Google returns an ID token. This token is then sent to the backend for verification.


Common Frontend Mistakes

Mistake Why It Causes Problems
Missing GoogleOAuthProvider Google Login will not initialize
Incorrect clientId Authentication will fail
Sending requests to the frontend instead of the backend OAuth verification must happen on the server
Forgetting to define environment variables The application won't be able to access the Google Client ID or backend URL

Backend Setup

Install Required Package

npm install google-auth-library

Configure Environment Variables

Create a .env file in the backend.

GOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.com
JWT_SECRET=your_jwt_secret_key

Create the Authentication Controller

Create a file named googleAuth.ts.

import { OAuth2Client } from "google-auth-library";
import User from "../models/user";
import jwt from "jsonwebtoken";

const client = new OAuth2Client(process.env.GOOGLE_CLIENT_ID);

export const googleAuth = async (req, res) => {
  try {
    const { credential } = req.body;

    const ticket = await client.verifyIdToken({
      idToken: credential,
      audience: process.env.GOOGLE_CLIENT_ID,
    });

    const payload = ticket.getPayload();

    const {
      email,
      name,
      sub: googleID,
    } = payload;

    let user = await User.findOne({ email });

    if (!user) {
      user = await User.create({
        email,
        username: name,
        googleID,
      });
    }

    const token = jwt.sign(
      {
        id: user._id,
      },
      process.env.JWT_SECRET,
      {
        expiresIn: "7d",
      }
    );

    res.status(200).json({
      token,
      user,
    });
  } catch (error) {
    console.error(error);

    res.status(401).json({
      message: "Google sign-in failed",
    });
  }
};

The backend verifies the ID token received from Google. If the token is valid, it either creates a new user or logs in an existing one before returning a JWT.


Register the Route

Import the controller into your main server file.

import { googleAuth } from "./controllers/googleAuth";

Register the route.

app.post("/api/v1/google-signin", googleAuth);

User Schema

A simple user schema is enough for Google authentication.

const userSchema = new mongoose.Schema({
  username: String,
  email: {
    type: String,
    required: true,
    unique: true,
  },
  password: String,
  googleID: String,
});

If your application supports both email/password authentication and Google Sign-In, keeping the password field optional is a common approach.


Authentication Flow

The complete authentication process looks like this:

User
   │
   ▼
Google Login Button
   │
   ▼
Google Authentication
   │
   ▼
Receive ID Token
   │
   ▼
Send Token to Express Backend
   │
   ▼
Verify Token with Google
   │
   ▼
Find or Create User
   │
   ▼
Generate JWT
   │
   ▼
Return JWT + User Data
   │
   ▼
Store JWT in Frontend

Final Project Structure

frontend
├── src
│   ├── components
│   │   └── GoogleAuth.tsx
│   ├── App.tsx
│   └── main.tsx
├── .env

backend
├── controllers
│   └── googleAuth.ts
├── models
│   └── user.ts
├── index.ts
└── .env

Conclusion

Integrating Google OAuth removes the friction of traditional sign-up forms while providing a secure authentication flow. Instead of managing passwords yourself, you rely on Google's identity platform, verify the ID token on your backend, and issue your own JWT for application access.

With this setup in place, users can sign in with a single click, while your backend remains responsible for authentication, authorization, and session management.

More from this blog

A

Aditya Kumar Gupta

28 posts

Hi there! I'm Aditya, a passionate Full-Stack Developer driven by a love for turning concepts into captivating digital experiences. With a blend of creativity and technical expertise