Seamless User Authentication with Google OAuth in React and Express

Nov 14, 2023

Nov 14, 2023

Nov 14, 2023

Hey there, tech enthusiasts! 👋 Rahil here, and I'm thrilled to take you on an exciting journey into implementing Google OAuth for our Study Planner app. In Week 3, we've dived headfirst into user authentication, and I'm here to guide you through the process step by step. Let's get started!

NPM Package for Google auth

The package I used to implement google oauth was called react-oauth/google. The command to install is:

npm install @react-oauth/google

Setting Up Google Cloud Project Credentials

First things first, to use Google OAuth, we need credentials from the Google Cloud project.

During setup, remember to add the following authorized JavaScript origins (Note: No trailing slash at the end):

  • http://localhost:3000

  • http://localhost:5000

Also, add the domain:

  • http://localhost

Missing out on these details could lead to some pesky errors down the road.

After setting up the credentials you will get your client id and client secret which will come in handy down the road.

Incorporating Google OAuth in React

If you've been using Create React App, you likely have an index.js file. This is where the magic begins. We'll start by adding the GoogleOAuthProvider context.

Don't forget to import the package:

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

The code snippet for reference:

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <GoogleOAuthProvider clientId='YourClientIDHere'>
    <React.StrictMode>
      <BrowserRouter>
        <Routes>
          <Route path="/*" element={<App />} />
        </Routes>
      </BrowserRouter>
    </React.StrictMode>
  </GoogleOAuthProvider>
);

Adding the Google Login Button

Now, let's keep it simple. The package provides a GoogleLogin component that makes adding a login button a breeze:

import { GoogleLogin } from '@react-oauth/google';
<GoogleLogin
  onSuccess={handleLogin}
  onError={handleFailure}
  buttonText=""
  useOneTap
  cookiePolicy={'single_host_origin'}
/>

Where GoogleLogin is a component for signing in which looks like this:

Also notice the component has onSuccess and onError props which are functions that execute on success and failure of login respectively.

Handling the Login Process

Time to get your hands dirty with code! Here's the handleLogin function:

const handleLogin = async (googleData) => {
  const res = await fetch('/api/google-login', {
    method: 'POST',
    body: JSON.stringify({
      token: googleData.credential,
    }),
    headers: {
      'Content-Type': 'application/json',
    },
  });
  const data = await res.json();
  setLoginData(data);
  localStorage.setItem('loginData', JSON.stringify(data));
};

This function is called upon a successful login and sends a POST request to the backend with the JWT token. The JWT token is crucial for user authentication. It looks something like this:

{
"credential": "eyJhbGmtpZCI6IjI3Yjg2ZGM2OTM4ZGMzMjdiMjA0MzMzYTI1MGViYjQzYjMyZTRiM2MiLCJ0eXAiOiJKV1QifQ.eyJpcdHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJuYmYiOjE2NjkzNDIxNTMsImF1ZCI6IjI3MTExOTQ1NzA0MS00Y2ZxdWdtNXY1aTFhNGNnZGV0NmNwZjgwMmZvY2VkaS5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsInN1YiI6IjEwMjU5MjEyMTA2MTU3MjIyMTM4NCIsImVtYWlsIjoia2hvai5iYWRhbWlAZ21haWwuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImF6cCI6IjI3MTExOTQ1NzA0MS00Y2ZxdWdtNXY1aTFhNGNnZGV0NmNwZjgwMmZvY2VkaS5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsIm5hbWUiOiJLaG9qIEJhZGFtaSIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vYS9BTG01d3UzMm1lckdfLTlpbkhSMkVFd1VZUDFxbndiZkg4TjJjZnlfcUhtLT1zOTYtYyIsImdpdmVuX25hbWUiOiJLaG9qIiwiZmFtaWx5X25hbWUiOiJCYWRhbWkiLCJpYXQiOjE2NjkzNDI0NTMsImV4cCI6MTY2OTM0NjA1MywianRpIjoiZTIzN2VjMGVmOWFkYWI2NjNhNGNkMmU4NjcxYWZiMjVlMzQ4NmRiYiJ9.qtPkkbtNLU9hKnsbDyFKTRm4Drdr1M0xoWgkyz4ymnxqg-HWh4ZKHARTzH7X6Gup-i5rJfQlA-AZ6XK7GvEkc_gARAu6azmpSbxgsR1etYhG_olqpI5j8Eb06TIGvKQZdRuR2O2wNhqOv0bpGGuMf8IrJzl1RgjfYu_YtHaCgsGGBmKwC-cRDwEuvTrCRiQe-jZkg0Vjmo8--2pkubfGXxbQJqFhi7ZLhTxsCXVCejpHAfzcpD5LszoymsVxcqAZjQOUcL8Fy78JydpEMghH-_unsESSkli8CpsAjTplCHywNu1_A3JIX59VoOh_dBet4HgvEzrlFjcsYSb8umvxIg",
"clientId": "27111941a4cgdet6cpf802focedi.apps.googleusercontent.com",
"select_by": "btn_confirm"
}

A resource I found helpful to learn about JWT was: What Is JWT and Why Should You Use JWT by web dev simplified.

Deciphering the JWT Token

To get user info like first name, last name, email, and profile photo, we need to decipher the JWT token in the backend with our secret key.

The backend is in express and we set up a basic server.js file like all express projects. This is the code for the api call on the backend.

function upsert(array, item) {
  const i = array.findIndex((_item) => _item.email === item.email);
  if (i > -1) array[i] = item;
  else array.push(item);
}

app.post('/api/google-login', async (req, res) => {
  console.log(req.body)
  const { token } = req.body;
  const ticket = await client.verifyIdToken({
    idToken: token,
    //audience: process.env.CLIENT_ID,
  });
  console.log(ticket)
  const { name, email, picture } = ticket.getPayload();
  upsert(users, { name, email, picture });
  res.status(201);
  res.json({ name, email, picture });
});

This code does a few things:

  • Logs the incoming request body (remove this in production).

  • Extracts the Google ID token from the request body.

  • Verifies the token using Google's client library, resulting in a ticket.

  • Extracts user information (name, email, picture) from the ticket payload.

  • Calls the upsert function to add or update user data in the `users` array.

  • Responds with user data as JSON and sets the HTTP status code to 201 (Created).

The 'audience: process.env.CLIENT_ID', line is commented out as it gave me an error while uncommented. The tutorial I was following had that line and it was working for them but for me the error was resolved by simply commenting that line out.

That's it! Now this user info is sent back to the frontend, and we can store it in a userState.

For a visual guide, check out our demo:

Conclusion

This was our journey through implementing user authentication with Google OAuth in React and Express.

Now, you're equipped to enhance your apps with seamless Google OAuth authentication.

Happy coding, and stay tuned for more tech insights from HackeroX!

Hey there, tech enthusiasts! 👋 Rahil here, and I'm thrilled to take you on an exciting journey into implementing Google OAuth for our Study Planner app. In Week 3, we've dived headfirst into user authentication, and I'm here to guide you through the process step by step. Let's get started!

NPM Package for Google auth

The package I used to implement google oauth was called react-oauth/google. The command to install is:

npm install @react-oauth/google

Setting Up Google Cloud Project Credentials

First things first, to use Google OAuth, we need credentials from the Google Cloud project.

During setup, remember to add the following authorized JavaScript origins (Note: No trailing slash at the end):

  • http://localhost:3000

  • http://localhost:5000

Also, add the domain:

  • http://localhost

Missing out on these details could lead to some pesky errors down the road.

After setting up the credentials you will get your client id and client secret which will come in handy down the road.

Incorporating Google OAuth in React

If you've been using Create React App, you likely have an index.js file. This is where the magic begins. We'll start by adding the GoogleOAuthProvider context.

Don't forget to import the package:

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

The code snippet for reference:

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <GoogleOAuthProvider clientId='YourClientIDHere'>
    <React.StrictMode>
      <BrowserRouter>
        <Routes>
          <Route path="/*" element={<App />} />
        </Routes>
      </BrowserRouter>
    </React.StrictMode>
  </GoogleOAuthProvider>
);

Adding the Google Login Button

Now, let's keep it simple. The package provides a GoogleLogin component that makes adding a login button a breeze:

import { GoogleLogin } from '@react-oauth/google';
<GoogleLogin
  onSuccess={handleLogin}
  onError={handleFailure}
  buttonText=""
  useOneTap
  cookiePolicy={'single_host_origin'}
/>

Where GoogleLogin is a component for signing in which looks like this:

Also notice the component has onSuccess and onError props which are functions that execute on success and failure of login respectively.

Handling the Login Process

Time to get your hands dirty with code! Here's the handleLogin function:

const handleLogin = async (googleData) => {
  const res = await fetch('/api/google-login', {
    method: 'POST',
    body: JSON.stringify({
      token: googleData.credential,
    }),
    headers: {
      'Content-Type': 'application/json',
    },
  });
  const data = await res.json();
  setLoginData(data);
  localStorage.setItem('loginData', JSON.stringify(data));
};

This function is called upon a successful login and sends a POST request to the backend with the JWT token. The JWT token is crucial for user authentication. It looks something like this:

{
"credential": "eyJhbGmtpZCI6IjI3Yjg2ZGM2OTM4ZGMzMjdiMjA0MzMzYTI1MGViYjQzYjMyZTRiM2MiLCJ0eXAiOiJKV1QifQ.eyJpcdHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJuYmYiOjE2NjkzNDIxNTMsImF1ZCI6IjI3MTExOTQ1NzA0MS00Y2ZxdWdtNXY1aTFhNGNnZGV0NmNwZjgwMmZvY2VkaS5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsInN1YiI6IjEwMjU5MjEyMTA2MTU3MjIyMTM4NCIsImVtYWlsIjoia2hvai5iYWRhbWlAZ21haWwuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImF6cCI6IjI3MTExOTQ1NzA0MS00Y2ZxdWdtNXY1aTFhNGNnZGV0NmNwZjgwMmZvY2VkaS5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsIm5hbWUiOiJLaG9qIEJhZGFtaSIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vYS9BTG01d3UzMm1lckdfLTlpbkhSMkVFd1VZUDFxbndiZkg4TjJjZnlfcUhtLT1zOTYtYyIsImdpdmVuX25hbWUiOiJLaG9qIiwiZmFtaWx5X25hbWUiOiJCYWRhbWkiLCJpYXQiOjE2NjkzNDI0NTMsImV4cCI6MTY2OTM0NjA1MywianRpIjoiZTIzN2VjMGVmOWFkYWI2NjNhNGNkMmU4NjcxYWZiMjVlMzQ4NmRiYiJ9.qtPkkbtNLU9hKnsbDyFKTRm4Drdr1M0xoWgkyz4ymnxqg-HWh4ZKHARTzH7X6Gup-i5rJfQlA-AZ6XK7GvEkc_gARAu6azmpSbxgsR1etYhG_olqpI5j8Eb06TIGvKQZdRuR2O2wNhqOv0bpGGuMf8IrJzl1RgjfYu_YtHaCgsGGBmKwC-cRDwEuvTrCRiQe-jZkg0Vjmo8--2pkubfGXxbQJqFhi7ZLhTxsCXVCejpHAfzcpD5LszoymsVxcqAZjQOUcL8Fy78JydpEMghH-_unsESSkli8CpsAjTplCHywNu1_A3JIX59VoOh_dBet4HgvEzrlFjcsYSb8umvxIg",
"clientId": "27111941a4cgdet6cpf802focedi.apps.googleusercontent.com",
"select_by": "btn_confirm"
}

A resource I found helpful to learn about JWT was: What Is JWT and Why Should You Use JWT by web dev simplified.

Deciphering the JWT Token

To get user info like first name, last name, email, and profile photo, we need to decipher the JWT token in the backend with our secret key.

The backend is in express and we set up a basic server.js file like all express projects. This is the code for the api call on the backend.

function upsert(array, item) {
  const i = array.findIndex((_item) => _item.email === item.email);
  if (i > -1) array[i] = item;
  else array.push(item);
}

app.post('/api/google-login', async (req, res) => {
  console.log(req.body)
  const { token } = req.body;
  const ticket = await client.verifyIdToken({
    idToken: token,
    //audience: process.env.CLIENT_ID,
  });
  console.log(ticket)
  const { name, email, picture } = ticket.getPayload();
  upsert(users, { name, email, picture });
  res.status(201);
  res.json({ name, email, picture });
});

This code does a few things:

  • Logs the incoming request body (remove this in production).

  • Extracts the Google ID token from the request body.

  • Verifies the token using Google's client library, resulting in a ticket.

  • Extracts user information (name, email, picture) from the ticket payload.

  • Calls the upsert function to add or update user data in the `users` array.

  • Responds with user data as JSON and sets the HTTP status code to 201 (Created).

The 'audience: process.env.CLIENT_ID', line is commented out as it gave me an error while uncommented. The tutorial I was following had that line and it was working for them but for me the error was resolved by simply commenting that line out.

That's it! Now this user info is sent back to the frontend, and we can store it in a userState.

For a visual guide, check out our demo:

Conclusion

This was our journey through implementing user authentication with Google OAuth in React and Express.

Now, you're equipped to enhance your apps with seamless Google OAuth authentication.

Happy coding, and stay tuned for more tech insights from HackeroX!

Lets build something
great together!

📞 Phone: +91-8329284312
📧 Email: contact@hackerox.com

Logo

📍Address:
Malad West, Mumbai - 400064

Lets build something
great together!

📞 Phone: +91-8329284312
📧 Email: contact@hackerox.com

Logo

📍Address: Malad West, Mumbai - 400064

Lets build something
great together!

📞 Phone: +91-8329284312
📧 Email: contact@hackerox.com

Logo

📍Address: Malad West, Mumbai - 400064