Introduction
Recently I was building a project in NextJS in which I needed to implement 'Sign in with Google' without third-party libraries like next-auth, or passport. In this article, we will cover a step-by-step guide for implementing OAuth on your NodeJS app.
Essentials
- A
MERN
Stack or aNextJS
app. - This guide uses typescript, but you can use JavaScript too if comfortable with that.
- A verified Google account from where we can use Google Developer features.
Google Application Setup
- Go to Google Cloud Console.
- Click on create a new project.
- Select the organization and click on Create Project.
- Select the recently made project from the above corner.
- Go to
APIs and Services
and selectOAuth consent screen
from the left sidebar. - Give your App a name that will be seen by the end users and the support email users can contact.
- Add a logo for your app, prescribed
120x120
dimensions. - Add your product's home page, and other links as asked.
- Add the domain of your application in the
Authorized Domains
section. - Go to the next screen and select the
userinfo.email
anduserinfo.profile
scope. - Go on to the next screen and add a couple or more email addresses to test your app with.
- After all the steps, go back to the dashboard.
- Go on to the credentials screen, from
Create credentials
, selectOAuth Client ID
, and select web application. - In the
Authorized JavaScript Origins
, add the following:- The link to localhost ->
http://localhost
- The link to localhost with port your applications usually runs on ->
http://localhost:3000
- The link to Google Developers Playground,
https://developers.google.com
- The link to your website, for example,
https://example.com
- Also add the link to the website if you want the authentication on a subdomain too, like
https://app.example.com
- The link to localhost ->
- In the
Authorized redirect URIs
, add the following:- The redirect link to localhost with the port your applications usually run on -> For example,
http://localhost:3000/auth/google/google-callback/oauth/login
. Ensure to includegoogle-callback
in the redirect URI, as stated in the guidelines. - The link to Google Developers Playground,
https://developers.google.com/oauthplayground
. - The redirect link to your website, for example,
https://example.com/auth/google/google-callback/oauth/login
, should be the same as that oflocalhost
.
- The redirect link to localhost with the port your applications usually run on -> For example,
- Create the credentials, and download the JSON of the credentials, where you will find the
client_id
andclient_secret
.
Writing the Code
In your NextJS project, create a file config/index.ts
Export the credentials that you stored in the .env
file
NEXT_PUBLIC_GOOGLE_OAUTH_CLIENT_ID="your oauth client id"
NEXT_PUBLIC_GOOGLE_OAUTH_CLIENT_SECRET="your oauth client secret"
NEXT_PUBLIC_GOOGLE_OAUTH_REDIRECT_URI="your oauth client redirect uri"
type GOOGLE_AUTH_KEYS =
| "client_id"
| "client_secret"
| "endpoint"
| "redirect_uri"
| "scopes";
export const oauth_google: Record<GOOGLE_AUTH_KEYS, string> = {
client_id: process.env.NEXT_PUBLIC_GOOGLE_OAUTH_CLIENT_ID || "",
client_secret: process.env.NEXT_PUBLIC_GOOGLE_OAUTH_CLIENT_SECRET || "",
endpoint: "https://accounts.google.com/o/oauth2/v2/auth",
redirect_uri: process.env.NEXT_PUBLIC_GOOGLE_OAUTH_REDIRECT_URI || "",
scopes: "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile"
}
Add a button to your login page, which should be built with guidelines as provided by Google: Branding Guidelines.
Add an onClick
event on the button to redirect user to the Google's sign-in page.
const query = {
client_id: oauth_google.client_id,
redirect_uri: oauth_google.redirect_uri,
response_type: "code",
scope: oauth_google.scopes,
};
const url = new URL(oauth_google.endpoint);
url.search = new URLSearchParams(query).toString();
window.location.href = url.toString()
After the user completes the authentication flow, google will redirect to your provided redirect_uri
in the .env
file. Keep that page as a frontend page instead of an API route.
Now for the further authentication process, we will need to make API calls to our back-end server whenever the redirect_uri
page loads where we will handle the data provided by Google after successful sign-in.
Note: In NextJS, you can leverage the getServerSideProps
, to make API requests to the server for the further authentication process. For ReactJS make the API calls by calling in useEffect
hook. Or if you are using any other framework, handle the API call as told in that.
In the search parameters of the returned page's URI, there is a parameter code
, send that to your server's API route, (POST /oauth/google/verify
here). Send this code in the request's body.
Backend
POST /oauth/google/verify
Create an API call to https://oauth2.googleapis.com/token
, to get the id_token
from the code we got from the request body.
const oauthRequest = {
url: new URL("https://oauth2.googleapis.com/token"),
params: {
client_id: oauth_google.client_id,
client_secret: oauth_google.client_secret,
code: req.body.code,
grant_type: "authorization_code",
redirect_uri: oauth_google.redirect_uri,
},
};
const oauthResponse = await axios.post(
oauthRequest.url.toString(),
null,
{ params: oauthRequest.params }
);
const oauthResponseData = oauthResponse.data;
In the oauthResponseData
, there is a parameter, id_token
. We will use this id_token
to get the user details.
To do this, we will install google-auth-library
which is Google's officially supported Node.js client library for using OAuth 2.0 authorization and authentication with Google APIs, and then use the verifyIdToken
method from the client to get the user details from the id_token
.
Create an OAuth Client to verify the ID token.
import { OAuth2Client } from "google-auth-library";
const client = new OAuth2Client();
export const fetchUserFromIdToken = async (idToken: string) => {
const ticket = await client.verifyIdToken({
idToken: idToken,
audience: oauth_google.client_id,
});
const payload = ticket.getPayload();
return payload;
};
After you have got the user details from the id_token
, return those details as the API response.
const user = await fetchUserFromIdToken(oauthResponseData.id_token);
return res
.status(200)
.json({ data: user, message: "Success" });
This user detail contains a lot of details, here is an example:
{
"iss": "Issuer of the token", // https://accounts.google.com here,
"azp": "The client_id of the authorized presenter",
"aud": "Identifies the audience that this ID token is intended for. It must be one of the OAuth 2.0 client IDs of your application.",
"sub": "The subject of the token. An identifier for the user, unique among all Google accounts and never reused.",
"email": "User's email",
"email_verified": "Boolean", // true usually
"at_hash": "Access token hash. Provides validation that the access token is tied to the identity token.",
"name": "Name from user's Google Account",
"picture": "The URL of the user's Google account's avatar",
"given_name": "First name from user's Google account",
"family_name": "Last name from user's Google account",
"locale": "The language locale of user's location", // 'en-GB'
"iat": "The time the ID token was issued, represented in Unix time (integer seconds).", // for example, 1708416251
"exp": "1. The time the ID token expires, represented in Unix time (integer seconds).", // for example, 1708419851
}
From here, you can use any details that you need to handle authentication in your project further.
Conclusion
This article demonstrates the use of Google OAuth for NodeJS applications.
Questions and feedback are most welcome. 😊
Top comments (1)
Hey, amazing article! It's helping me with integrating Google Sign-in with my webapp. I had to convert some of the code to Vanilla JavaScript, but that was pretty easy!
I did find a couple of errors in your code (errors at least for me):
code: req.body.code
, the code supplied is not inreq.body
, instead it is given throughreq.query
. It is also important to note that after successful login it redirects to theGET
URL, notPOST
.oauthResponseData = oauthResponse.data
, butoauthResponse
does not have a childdata
. Instead, just useoauthResponse
. You can then useid_token
fromoauthResponse
later.Despite these, I found the article very straightforward. It was very easy to use the method to create a login link and get user details, and also sticks with the idea of being dependent-free. Thanks for this one!