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


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

```bash
npm install @react-oauth/google
```

---

## Configure Environment Variables

Create a `.env` file in your frontend project.

```env
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.

```tsx
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`.

```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

```bash
npm install google-auth-library
```

---

## Configure Environment Variables

Create a `.env` file in the backend.

```env
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`.

```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.

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

Register the route.

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

---

# User Schema

A simple user schema is enough for Google authentication.

```ts
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:

```text
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

```text
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.
