Google has a wealth of APIs that we can interact with. At the time of writing, there’s more than 200 APIs available, including YouTube, Google Calendar and Gmail, and many more.
To integrate with Google APIs, it’s necessary to authenticate with Google and acquire a credential. In this tutorial, we’ll walk you through how to authenticate with Google using TypeScript.
For a practical example, we’ll demonstrate how to use the acquired refresh token to access the Google Calendar API. You can apply the same approach to access any other publicly curated Google API.
First, go to the Google Cloud Platform to create a project. The name of the project doesn’t matter, although it may be helpful to name the project to align with the API you intend to consume. That’s what we’ll do here as we plan to integrate with the Google Calendar API:
The project is the container in which the OAuth 2.0 client ID will be housed. Now that we’ve created the project, let’s go to the credentials screen and create an OAuth Client ID using the Create Credentials dropdown:
You’ll likely have to create an OAuth consent screen before you can create the OAuth Client ID. Doing that feels a little daunting; there are many questions that have to be answered because the consent screen can be used for a variety of purposes beyond the API authentication we’re looking at today.
When challenged, you can generally accept the defaults and proceed. The user type you’ll require will be External:
You’ll also be prompted to create an app registration. All that’s really required here is a name (which can be anything) and your email address:
You don’t need to worry about scopes. You can either plan to publish the app or set yourself up to be a test user; you’ll need to do one or the other to authenticate with the app. Continuing to the end of the journey should provide you with the OAuth consent screen, which you need to then create the OAuth client ID.
Creating the OAuth client ID is slightly confusing because the Application type required is TVs and Limited Input devices.
We’re using this type of application because we want to acquire a refresh token that we’ll be able to use in future to acquire tokens to access the Google APIs.
Once it’s created, you’ll be able to download the client ID from the Google Cloud Platform:
When you download it, it should look something like this:
{ "installed": { "client_id": "CLIENT_ID", "project_id": "PROJECT_ID", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_secret": "CLIENT_SECRET", "redirect_uris": ["urn:ietf:wg:oauth:2.0:oob", "http://localhost"] } }
You’ll need the client_id
, client_secret
, and redirect_uris
. Keep them in a safe place and don’t commit client_id
and client_secret
to source control.
Now we’ve got our client_id
and client_secret
, we’re ready to write a simple node command line application that we can use to obtain a refresh token. This is a multistage process that will end up looking like this:
client_id
and client_secret
. In return, it will provide an authentication URLclient_id
, client_secret
and the code. It will acquire and provide users with a refresh tokenLet’s start coding. We’ll initialize a TypeScript Node project like so:
mkdir src cd src npm init -y npm install googleapis ts-node typescript yargs @types/yargs @types/node npx tsc --init
We’ve added a number of dependencies that will allow us to write a TypeScript Node command-line application. We’ve also added a dependency to the googleapis
package, which describes itself as follows:
Node.js client library for using Google APIs. Support for authorization and authentication with OAuth 2.0, API Keys and JWT tokens is included.
We’re going to make use of the OAuth 2.0 part. We’ll start our journey by creating a file called google-api-auth.ts
:
import { getArgs, makeOAuth2Client } from "./shared"; async function getToken() { const { clientId, clientSecret, code } = await getArgs(); const oauth2Client = makeOAuth2Client({ clientId, clientSecret }); if (code) await getRefreshToken(code); else getAuthUrl(); async function getAuthUrl() { const url = oauth2Client.generateAuthUrl({ // 'online' (default) or 'offline' (gets refresh_token) access_type: "offline", // scopes are documented here: https://developers.google.com/identity/protocols/oauth2/scopes#calendar scope: ["https://www.googleapis.com/auth/calendar", "https://www.googleapis.com/auth/calendar.events"], }); console.log(`Go to this URL to acquire a refresh token:\n\n${url}\n`); } async function getRefreshToken(code: string) { const token = await oauth2Client.getToken(code); console.log(token); } } getToken();
And a common file named shared.ts
, which google-api-auth.ts
imports and we’ll reuse later:
import { google } from "googleapis"; import yargs from "yargs/yargs"; const { hideBin } = require("yargs/helpers"); export async function getArgs() { const argv = await Promise.resolve(yargs(hideBin(process.argv)).argv); const clientId = argv['clientId'] as string; const clientSecret = argv['clientSecret'] as string; const code = argv.code as string | undefined; const refreshToken = argv.refreshToken as string | undefined; const test = argv.test as boolean; if (!clientId) throw new Error('No clientId '); console.log('We have a clientId'); if (!clientSecret) throw new Error('No clientSecret'); console.log('We have a clientSecret'); if (code) console.log('We have a code'); if (refreshToken) console.log('We have a refreshToken'); return { code, clientId, clientSecret, refreshToken, test }; } export function makeOAuth2Client({ clientId, clientSecret, }: { clientId: string; clientSecret: string; }) { return new google.auth.OAuth2( /* YOUR_CLIENT_ID */ clientId, /* YOUR_CLIENT_SECRET */ clientSecret, /* YOUR_REDIRECT_URL */ "urn:ietf:wg:oauth:2.0:oob" ); }
The getToken
function above does two things:
client_id
and client_secret
, it will obtain an authentication URLclient_id
, client_secret
, and code
, it will obtain a refresh token (scoped to access the Google Calendar API)We’ll add an entry to our package.json
, which will allow us to run our console app:
"google-api-auth": "ts-node google-api-auth.ts"
Now we’re ready to acquire the refresh token. We’ll run the following command, substituting in the appropriate values:
npm run google-api-auth -- --clientId CLIENT_ID --clientSecret CLIENT_SECRET
Click on the URL that is generated in the console. It should open up a consent screen in the browser, which looks like this:
Authenticate and grant consent and you should get a code:
Then (quickly) paste the acquired code into the following command:
npm run google-api-auth -- --clientId CLIENT_ID --clientSecret CLIENT_SECRET --code THISISTHECODE
The refresh_token
(alongside much else) will be printed to the console. Grab it and put it somewhere secure. Again, no storing in source control!
It’s worth taking a moment to reflect on what we’ve done. We acquired a refresh token, which involved a certain amount of human interaction. We had to run a console command, do some work in a browser, and run another command.
You wouldn’t want to do this repeatedly because it involves human interaction. Intentionally, it cannot be automated. However, once you’ve acquired the refresh token, you can use it repeatedly until it expires (which may be never, or at least years in the future).
Once you have the refresh token and you’ve stored it securely, you have what you need to automate an API interaction.
Let’s test out our refresh token by attempting to access the Google Calendar API. We’ll create a calendar.ts
file:
import { google } from "googleapis"; import { getArgs, makeOAuth2Client } from "./shared"; async function makeCalendarClient() { const { clientId, clientSecret, refreshToken } = await getArgs(); const oauth2Client = makeOAuth2Client({ clientId, clientSecret }); oauth2Client.setCredentials({ refresh_token: refreshToken }); const calendarClient = google.calendar({ version: "v3", auth: oauth2Client, }); return calendarClient; } async function getCalendar() { const calendarClient = await makeCalendarClient(); const { data: calendars, status } = await calendarClient.calendarList.list(); if (status === 200) { console.log('calendars', calendars); } else { console.log('there was an issue...', status); } } getCalendar();
The getCalendar
function above uses the client_id
, client_secret
, and refresh_token
to access the Google Calendar API and retrieve the list of calendars.
We’ll add an entry to our package.json
, which will allow us to run this function:
"calendar": "ts-node calendar.ts",
Now we’re ready to test calendar.ts
. We’ll run the following command, substituting in the appropriate values:
npm run calendar -- --clientId CLIENT_ID --clientSecret CLIENT_SECRET --refreshToken REFRESH_TOKEN
When we run for the first time, we may encounter a self explanatory message which tells us that we need enable the calendar API for our application:
(node:31563) UnhandledPromiseRejectionWarning: Error: Google Calendar API has not been used in project 77777777777777 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/calendar-json.googleapis.com/overview?project=77777777777777 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.
Once enabled, we can run successfully for the first time. We should see something like this showing up in the console:
This demonstrates that we’re successfully integrating with a Google API using our refresh token.
We’ve demonstrated how to integrate with the Google Calendar API, but that is not the limit of what we can do. As we discussed earlier, Google has more than 200 APIs we can interact with following the same steps for authentication outlined in this tutorial.
If you want to integrate with the YouTube API or Gmail API, for example, you could simply follow the above steps using the corresponding scope and build an integration against that API. The approach outlined by this tutorial is the key to integrating with a multitude of Google APIs. Happy integrating!
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowThe useReducer React Hook is a good alternative to tools like Redux, Recoil, or MobX.
Node.js v22.5.0 introduced a native SQLite module, which is is similar to what other JavaScript runtimes like Deno and Bun already have.
Understanding and supporting pinch, text, and browser zoom significantly enhances the user experience. Let’s explore a few ways to do so.
Playwright is a popular framework for automating and testing web applications across multiple browsers in JavaScript, Python, Java, and C#. […]
One Reply to "How to authenticate and access Google APIs using OAuth 2.0"
Thank you, I was looking for hours and in the end it was so simple.