James Aldridge
James Aldridge

Reputation: 69

How to get a logged in users google access token when using clerk for auth

In my NextJS app I am using clerk for auth (Google SSO) and I want to be able to create a google meet event through the UI on behalf of the signed in user. I believe the way to do this is once a user has used signed in through google sso I should be able to retrieve their google access token that can be used to query the google calendar api and make the event. I have granted https://www.googleapis.com/auth/calendar.events https://www.googleapis.com/auth/calendar as additional scopes in clerk for Google SSO so now users can authorise these on sign up or later on through the clerk ui.

The issue is getting the google access token. It is not in the user object by default. I don't know how I can obtain it. Maybe there is some way to obtain it at sign in and save it to the users metadata with a webhook? I think it should be easy or at least possible as otherwise I don't know why you can grant additional scopes for identity providers in clerk.

Would really appreciate any assistance. Cheers

I've searched the docs https://clerk.com/docs/authentication/social-connections-oauth#configure-additional-o-auth-scopes introduced additional o-auth scopes for google calendar api. Can't find anything on getting the google access token. GPT-4 can't solve it, thinks it should be in the user object by default which it isn't.

Upvotes: 4

Views: 7555

Answers (3)

andersra
andersra

Reputation: 1135

You can use clerkClient and currentUser exported from @clerk/nextjs.

import { clerkClient, currentUser } from '@clerk/nextjs';

export async function currentUserOauthAccessToken() {
  const user = await currentUser();
  if (!user) {
    return;
  }
  await clerkClient.users.getUserOauthAccessToken(user.id, 'oauth_google');
}

With this access token you can now invoke the Google APIs.

Upvotes: 0

yoshinator
yoshinator

Reputation: 485

So after some digging around I figured this out. You need three key packages to make this work.

Also you need to have the scopes added that you will be using. In my example below, I use the gmail scope, so add it from your clerk dashboard. You will need your own Google Credentials with ClientID and secret set on the clerk dashboard aswell.

import { auth } from '@clerk/nextjs'
import clerk from '@clerk/clerk-sdk-node'
import { google } from 'googleapis'

You're going to need to auth to get your userId. You're going to need clerk from the sdk to get the access Token. You're going to need google to access the gmail api for my example.

after that the rest is pretty trivial.

Here is a route.ts file I created that has this working.

// src/app/api/gmail/route.ts
import { auth } from '@clerk/nextjs'
import { NextResponse } from 'next/server'
import { google } from 'googleapis'
import clerk from '@clerk/clerk-sdk-node'

export async function GET(req: Request) {
  try {
    const { userId } = auth()

    // this returns an array of OauthAccessToken objects I'm just getting the first one
    const [OauthAccessToken] = await clerk.users.getUserOauthAccessToken(
      userId || '',
      'oauth_google'
    )

    // this is the token I need to use to make requests to the gmail api
    // destructuring it here for clarity you can also just use OauthAccessToken.token below
    const { token } = OauthAccessToken
R
    if (!token) {
      return new NextResponse('Unauthorized NO TOKEN', { status: 401 })
    }

    // this is the gmail api client, you can use this to make 
    // any request to the gmail api you can use any other 
    // google.whatever api you need. Here is we make use of 
    // the token we got from clerk passed in the headers
    const gmail = google.gmail({
      version: 'v1',
      headers: { Authorization: `Bearer ${token}` },
    })
    const res = await gmail.users.labels.list({
      userId: 'me',
    })

    return NextResponse.json(res.data.labels)
  } catch (error) {
    console.log('[GMAIL ERROR]', error)
    return new NextResponse('Internal error', { status: 500 })
  }
}

I hope this answers the question with a little more clarity.

Upvotes: 3

James Aldridge
James Aldridge

Reputation: 69

Clerk Devs linked me appropriate docs.

In nextjs you can use clerkClient.users in the backend to retrieve it

https://clerk.com/docs/reference/backend-api/tag/Users#operation/GetOAuthAccessToken

https://api.clerk.dev/v1/users/{user_id}/oauth_access_tokens/{provider}

Upvotes: 1

Related Questions