Integrate Google OAuth Client ID in Vue 3: Step-by-Step Guide for Secure Authentication

Hariharan C
6 min readJun 15, 2024

--

In this blog, we will build a project on Google OAuth integration using Vue.js 3. I will share the detailed process of how I integrated this powerful feature into a Vue.js 3 project and discuss the challenges I faced along the way. Let’s get started!

Create a Vue Project

First, create a Vue project on your local system with the following command. Open your terminal and type:

vue create <project-name>

This command will create a new Vue project on your local system.

Configure Google OAuth

Next, go to the Google Cloud Console and log in using your Google account. After completing the login process, navigate to the OAuth consent screen in the left menu. There are four steps in this section:

  1. Set the application information, including the app name, user support email, application logo, and app domain.
  2. For the app domain, use the URL: http://localhost:8080

Then, add the developer email ID and click “Save and Continue” for all the remaining steps.

Once done, go to the “Credentials” section. Click “Create Credentials” at the top, then select “OAuth Client ID.” Choose the application type “Web application” and add the Authorized JavaScript origins and Authorized redirect URLs as shown in the image below.

Copy the Client ID

Once you have completed the process, copy the Client ID. This Client ID is crucial for the integration and will be used extensively in your project.

Project Structure

Here is your project structure:

my-vue-app/
├── public/
│ ├── index.html
│ └── …
├── src/
│ ├── assets/
│ ├── components/
│ │ ├── GoogleAuth.vue
│ ├── views/
│ │ ├── Home.vue
│ ├── App.vue
│ ├── main.js
│ ├── router.js
├── server/
│ ├── index.js
│ ├── package.json
│ └── …
├── .gitignore
├── package.json
├── README.md
└── …

Required Libraries for This Project

Ensure that all the necessary libraries are properly installed. You will need:

  • google-auth-library
  • express
  • cors
  • crypto

Install them using npm or yarn to avoid any issues during development. Here’s how you can install them with npm:

npm install google-auth-library express cors crypto

Or with yarn:

yarn add google-auth-library express cors crypto

Server Setup

Create the server in server/index.js:

const express = require(‘express’);
const cors = require(‘cors’);
const session = require(‘express-session’);
const { OAuth2Client } = require(‘google-auth-library’);
const client = new OAuth2Client(‘GOOGLE-CLIENTid.apps.googleusercontent.com’);
const crypto = require(‘crypto’);

const app = express();

// Generate a secure secret key for session encryption
const secret = crypto.randomBytes(64).toString(‘hex’);

// Configure CORS to allow requests from the frontend
app.use(cors({
origin: ‘http://localhost:8080',
credentials: true,
}));

// Middleware to parse JSON requests
app.use(express.json());

// Configure session middleware
app.use(session({
secret: secret, // Use the generated secret key
resave: false, // Don’t save the session if it wasn’t modified
saveUninitialized: true, // Save uninitialized sessions
cookie: {
maxAge: 300000, // Session expires after 5 minutes (300,000 ms)
},
}));

// Endpoint to verify the Google ID token
app.post(‘/verify-token’, async (req, res) => {
const { token } = req.body;

try {
// Verify the ID token using the Google OAuth2 client
const ticket = await client.verifyIdToken({
idToken: token,
audience: ‘GOOGLE-CLIENTid.apps.googleusercontent.com’,
});

const payload = ticket.getPayload();

// Store user information in the session
req.session.user = payload;
req.session.cookie.expires = new Date(Date.now() + 300000);
req.session.cookie.maxAge = 300000;

res.json({ verified: true, payload });

} catch (error) {
console.error(‘Error verifying token:’, error);
res.status(401).json({ verified: false });
}
});

// Endpoint to handle logout and destroy the session
app.post(‘/logout’, (req, res) => {
req.session.destroy(err => {
if (err) {
console.error(“Error destroying session:”, err);
res.status(500).send(‘Error signing out’);
} else {
res.clearCookie(‘connect.sid’); // Clear the session cookie
res.send({ success: true });
}
});
});

// Endpoint to check session status
app.get(‘/session-info’, (req, res) => {
if (req.session.user) {
res.json({ sessionActive: true, user: req.session.user });
} else {
res.json({ sessionActive: false });
}
});

// Start the server on port 3000
app.listen(3000, () => {
console.log(‘Server is running on http://localhost:3000');
});

Vue Component

Create the Vue component in src/components/GoogleAuth.vue:

<template>
<div id=”app”>
<! — Show “Sign in with Google” button if the user is not signed in →
<button v-if=”!isSignedIn” @click=”handleAuthClick”>Sign in with Google</button>

<! — Show “Sign out” button if the user is signed in →
<button v-else @click=”signOut”>Sign out</button>

<! — Display user information if the user is signed in →
<div v-if=”isSignedIn”>
<h3>User Information</h3>
<p><strong>Name:</strong> {{ userInfo.name }}</p>
<p><strong>Email:</strong> {{ userInfo.email }}</p>
<img :src=”userInfo.picture” alt=”User Picture” />
</div>
</div>
</template>

<script>
export default {
name: ‘App’,
data() {
return {
isSignedIn: false, // Track if the user is signed in
userInfo: null, // Store user information
};
},
created() {
this.checkSession(); // Check session status when component is created
setInterval(this.checkSession, 60000); // Check session status every minute
},
methods: {
handleAuthClick() {
// Initialize Google Sign-In if the Google API is loaded
if (window.google) {
window.google.accounts.id.initialize({
client_id: ‘GOOGLE-CLIENTid.apps.googleusercontent.com’, // Google Client ID
callback: this.handleCredentialResponse, // Callback function after sign-in
auto_select: false, // Disable auto-select for extra security
});
window.google.accounts.id.prompt(); // Display the One Tap prompt
} else {
console.error(“Google API script not loaded.”);
}
},
async handleCredentialResponse(response) {
try {
console.log(‘Encoded JWT ID token: ‘ + response.credential);
const user = this.parseJwt(response.credential); // Parse the JWT to get user info

// Verify the token on the server side
const verifiedUser = await this.verifyTokenOnServer(response.credential);
if (verifiedUser) {
this.isSignedIn = true;
this.userInfo = user; // Store user info if verification is successful
} else {
throw new Error(‘Token verification failed.’);
}
} catch (error) {
console.error(‘Error during credential response handling:’, error);
}
},
async signOut() {
try {
// Call the server to destroy the session
await fetch(‘http://localhost:3000/logout’, {
method: ‘POST’,
credentials: ‘include’,
});
this.isSignedIn = false;
this.userInfo = null; // Clear user info after sign-out
console.log(‘User signed out.’);
} catch (error) {
console.error(‘Error signing out:’, error);
}
},
async verifyTokenOnServer(token) {
try {
// Send the token to the server for verification
const response = await fetch(‘http://localhost:3000/verify-token’, {
method: ‘POST’,
headers: {
‘Content-Type’: ‘application/json’,
},
credentials: ‘include’,
body: JSON.stringify({ token }),
});
if (response.ok) {
const data = await response.json();
return data.verified; // Return verification status
} else {
console.error(‘Token verification failed:’, response.statusText);
return false;
}
} catch (error) {
console.error(‘Error during token verification:’, error);
return false;
}
},
async checkSession() {
try {
// Check the session status on the server
const response = await fetch(‘http://localhost:3000/session-info’, {
method: ‘GET’,
credentials: ‘include’,
});
if (response.ok) {
const data = await response.json();
if (data.sessionActive) {
this.isSignedIn = true;
this.userInfo = data.user; // Update user info if session is active
} else {
this.isSignedIn = false;
this.userInfo = null; // Clear user info if session is inactive
}
} else {
console.error(‘Failed to check session:’, response.statusText);
}
} catch (error) {
console.error(‘Error checking session:’, error);
}
},
parseJwt(token) {
// Decode the JWT token to get the payload
const base64Url = token.split(‘.’)[1];
const base64 = base64Url.replace(/-/g, ‘+’).replace(/_/g, ‘/’);
const jsonPayload = decodeURIComponent(atob(base64).split(‘’).map(function(c) {
return ‘%’ + (‘00’ + c.charCodeAt(0).toString(16)).slice(-2);
}).join(‘’));
return JSON.parse(jsonPayload); // Parse and return the JSON payload
},
},
};
</script>

Main App Setup

Update src/App.vue:

<template>
<HelloWorld msg=”Welcome to Login Page”/>
<LoginPage />
</template>

<script>
import HelloWorld from ‘./components/HelloWorld.vue’
import LoginPage from “./components/Login.vue”

export default {
name: ‘App’,
components: {
HelloWorld,
LoginPage
}

}
</script>

<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
img{
border-radius: 10px;
}

</style>

Running the Application

Place the Google Client ID properly and run the application using:

npm run serve

Start the server:

node server/index.js

Now, you have successfully integrated Google OAuth into your Vue.js 3 project. Enjoy secure authentication with Google!

Feedback

We hope you found this guide helpful in integrating Google OAuth with Vue.js 3. Your feedback is valuable to us, so please share your thoughts and experiences in the comments section below. If you encountered any issues or have suggestions for improvement, let us know! Your input will help us enhance the quality of our tutorials and better serve the developer community. Thank you for reading!

Share on LinkedIn

If you enjoyed this tutorial, please share it on LinkedIn to help others learn and improve their Vue.js skills. Together, we can build a stronger developer community!

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Hariharan C
Hariharan C

Written by Hariharan C

Hi myself Hariharan I’m an ethical hacker, Bughunter, Cybersecurity researcher, GUI Designer, Python based network and bughunting tool Designer etc…..

No responses yet

Write a response