Google OAuth with Nodejs and React
Lets implement Google sign in functionality in a the React application without any external library. I will be using Google OAuth 2.0 and Google apis to integrate it in our NodeJs application and at the end we will be calling our nodejs endpoints from out frontend applications like React, Angular, Vue or our vanilla JavaScript
Table of Content
- Configure Google Consent Screen
- Generate Client Id and Client Secret
- Initialize a Node Js application
- Setup .env file
- Building the Application and Integrate Google Apis
- Connect with Frontend
- Lets Break down what actually happens?
- Source Code 😉
Before i start lets see where we should configure the google consent screen
Check here
Configure Google Consent Screen
- Visit the above link
- Click on select a project and there click on New Project
- Give a project name and create a project
- Now Click on Create Credentials and select OAuth Client Id
- Click on Configure Consent Screen
- Select External and Create
- Fill the required * fields
- Click on Save and Continue
- Click on Add or Remove Scopes and Select First two options and click on update
- In the next screen click on Add users that you will using for testing purposes
- Click an Save and Continue and on the next screen click on back to dashboard
Step 1
Step 2
Step 3
Generate Client Id and Client Secret
- Again Click on Create Credentials from top and select OAuth Client Id
- Select Web Application
- Now follow carefully
- Under Authorized redirect URIs we have to add our node js endpoints that google will use to redirect after a successful signin
- let put the value
- URIs 1 : http://localhost:8080/api/oauth/google/success
- URIs 2 : https://YOUR DOMAIN/api/oauth/google/success [This is for production use and can be skipped]
- Click on Create and you can see out client Id and client secret save it somewhere
Step 4
Initialize A Node Js Application
- Run npm init -y
- Create index.js, .env file, routes folder and controller folder
- Run npm i express dotenv jsonwebtoken
Setup .env file
1 Â //.env
2 Â GOOGLE_CLIENT_ID=YOUR_CLIENT_ID
3 Â GOOGLE_CLIENT_SECRET=YOUR_CLIENT_SECRET
4 Â REDIRECT_URI=http://localhost:8080/api/oauth/google/success
5 Â JWT_SECRET_KEY=YOUR_SECRET_KEY //can be anything
Building the Application and Integrate Google Apis
1 Â //package.json
2 Â
3 Â "type": "module"
4 Â "scripts" : {
5 Â "start": "node index"
6 Â }
7 Â
8 Â
1 Â //Index.js
2 Â
3 Â import express from "express";
4 Â import env from 'dotenv';
5 Â import { oauthRouter } from "./routes/oauth.route.js";
6 Â
7 Â env.config();
8 Â
9 Â const server = express();
10 Â
11 Â server.use('/api/oauth', oauthRouter);
12 Â
13 Â server.listen(8080, () => {
14 Â console.log('Server listening ...')
15 Â })
1 Â // routes/oauth.route.js
2 Â
3 Â import { Router } from "express";
4 Â import { handleGoogleConsentScreen, onSuccessGoogleOAuth, verifyToken, signout } from "../controllers/oauth.controller.js";
5 Â
6 Â const oauthRouter = Router();
7 Â
8 Â oauthRouter.get('/google', handleGoogleConsentScreen);
9 Â oauthRouter.get('/google/success', onSuccessGoogleOAuth);
10 Â oauthRouter.post('/verify/:token', verifyToken);
11 Â oauthRouter.get('/signout', signout);
12 Â
13 Â export { oauthRouter }
1 Â /*
2 Â * **** Processes involved in implementation of Google OAuth ****
3 Â *
4 Â * Configure consent screen and get Client Id and Client Secret
5 Â * Check: https://console.cloud.google.com/apis/credentials
6 Â *
7 Â * Creating google consent screen url with client id
8 Â * Google redirects the provided redirect uri with a code in params
9 Â * Getting access_token and id_token form google apis using the code
10 Â * Getting user details using the access token and token id
11 Â */
12 Â
13 Â import jwt from 'jsonwebtoken';
14 Â
15 Â //This funchtion will handle to show google consent screen
16 Â const handleGoogleConsentScreen = async (req, res) => {
17 Â
18 Â const url = new URL('https://accounts.google.com/o/oauth2/v2/auth');
19 Â
20 Â const options = {
21 Â redirect_uri: process.env.REDIRECT_URI,
22 Â client_id: process.env.GOOGLE_CLIENT_ID,
23 Â access_type: 'offline',
24 Â response_type: 'code',
25 Â prompt: 'consent',
26 Â scope: [
27 Â 'https://www.googleapis.com/auth/userinfo.profile',
28 Â 'https://www.googleapis.com/auth/userinfo.email',
29 Â ].join(' ')
30 Â }
31 Â
32 Â url.search = new URLSearchParams(options);
33 Â
34 Â return res.redirect(url);
35 Â }
36 Â
37 Â const getGoogleAccessTokens = async (code) => {
38 Â const url = new URL('https://oauth2.googleapis.com/token');
39 Â
40 Â const tokenExchangeOptions = {
41 Â code,
42 Â client_id: process.env.GOOGLE_CLIENT_ID,
43 Â client_secret: process.env.GOOGLE_CLIENT_SECRET,
44 Â redirect_uri: process.env.REDIRECT_URI,
45 Â grant_type: 'authorization_code',
46 Â }
47 Â
48 Â url.search = new URLSearchParams(tokenExchangeOptions);
49 Â
50 Â let response = await fetch(url, {
51 Â method: 'POST',
52 Â headers: {
53 Â 'Content-Type': 'application/x-www-form-urlencoded',
54 Â }
55 Â })
56 Â
57 Â let data = await response.json();
58 Â
59 Â return data;
60 Â }
61 Â
62 Â //This funchtion will be to get userinfo by using acces_token and id_token
63 Â const getGoogleUserInfo = async (access_token, id_token) => {
64 Â
65 Â const url = new URL('https://www.googleapis.com/oauth2/v1/userinfo');
66 Â
67 Â const options = {
68 Â alt: 'json',
69 Â access_token
70 Â }
71 Â
72 Â url.search = new URLSearchParams(options);
73 Â
74 Â let response = await fetch(url, {
75 Â headers: {
76 Â Authorization: `Bearer ${id_token}`,
77 Â },
78 Â })
79 Â
80 Â let data = await response.json();
81 Â return data;
82 Â }
83 Â
84 Â const onSuccessGoogleOAuth = async (req, res) => {
85 Â
86 Â const { code } = req.query;
87 Â
88 Â try {
89 Â let { access_token, id_token } = await getGoogleAccessTokens(code);
90 Â
91 Â let data = await getGoogleUserInfo(access_token, id_token);
92 Â
93 Â let sessionToken = jwt.sign(data, process.env.JWT_SECRET_KEY);
94 Â
95 Â const date = new Date();
96 Â date.setDate(date.getDate() + 30);
97 Â
98 Â res.cookie('session', sessionToken, {
99 Â path: '/',
100 Â expires: date,
101 Â domain: process.env.COOKIE_DOMAIN,
102 Â })
103 Â
104 Â return res.redirect(process.env.FRONTEND_URL);
105 Â
106 Â } catch (error) {
107 Â return res.redirect(`${process.env.FRONTEND_URL}?error=Something wen wrong`);
108 Â }
109 Â }
110 Â
111 Â const verifyToken = (req, res) => {
112 Â
113 Â const { token } = req.params;
114 Â
115 Â try {
116 Â let validation = jwt.verify(token, process.env.JWT_SECRET_KEY);
117 Â return res.send({ validation });
118 Â } catch (error) {
119 Â return res.status(404).send({ validation: null });
120 Â }
121 Â }
122 Â
123 Â const signout = (req, res) => {
124 Â res.clearCookie('session', { domain: process.env.COOKIE_DOMAIN });
125 Â return res.redirect(process.env.FRONTEND_URL);
126 Â }
127 Â
128 Â export { handleGoogleConsentScreen, onSuccessGoogleOAuth, verifyToken, signout }
Now our nodejs endpoints are ready. lets connect it to our frontend and i will be using nextjs, a react framework
Connect with Frontend
- Initialize a next app with npx create-next-app
- Now lets create a simple button to signin with google
1 Â // app/page.js
2 Â
3 Â import Link from 'next/link'
4 Â import styles from './page.module.css'
5 Â import { cookies } from 'next/headers';
6 Â
7 Â
8 Â const getSession = async () => {
9 Â let token = cookies().get('session')?.value;
10 Â
11 Â let response = await fetch(`http://localhost:8080/api/oauth/verify/${token}`);
12 Â let { validation } = await response.json();
13 Â
14 Â return validation;
15 Â }
16 Â
17 Â export default async function Home() {
18 Â
19 Â let user = await getSession();
20 Â
21 Â return (
22 Â <main className={styles.main}>
23 Â
24 Â {user ? (
25 Â <div>
26 Â <img src={user.picture} alt={user.name} />
27 Â <h2> {user.name} </h2>
28 Â <p> {user.email} </p>
29 Â <Link href={'http://localhost:8080/api/oauth/signout'}>
30 Â <button> Signout </button>
31 Â </Link>
32 Â </div>
33 Â ) : (
34 Â <Link href={'http://localhost:8080/api/oauth/google'}>
35 Â <button> Signin with Google </button>
36 Â </Link>
37 Â )}
38 Â
39 Â </main>
40 Â )
41 Â }
Let's Break down what actually happens?
Source Code 😉
Check here
Thank you😊 for joining me with the journey of Google OAuth integration with React and Node js. Hope this blog helps you a lot.