Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GoogleAuth can no longer be used with googleapis: Type 'GoogleAuth<JSONClient>' is not assignable to type 'string | OAuth2Client | BaseExternalAccountClient | GoogleAuth<JSONClient> | undefined' #1402

Closed
sceee opened this issue Apr 28, 2022 · 47 comments
Assignees
Labels
priority: p2 Moderately-important priority. Fix may not be included in next release. type: bug Error or flaw in code with unintended results or allowing sub-optimal usage patterns.

Comments

@sceee
Copy link

sceee commented Apr 28, 2022

After updating google-auth-library-nodejs from v7.14.1 to v8.0.1, the following Typescript compile error occurs:

Type 'GoogleAuth<JSONClient>' is not assignable to type 'string | OAuth2Client | BaseExternalAccountClient | GoogleAuth<JSONClient> | undefined'.
  Type 'import(".../node_modules/google-auth-library/build/src/auth/googleauth").GoogleAuth<import(".../node_modules/google-auth-library/build/src/auth/googleauth").JSONClient>' is not assignable to type 'import(".../node_modules/google-gax/node_modules/google-auth-library/build/src/auth/googleauth").GoogleAuth<import(".../node_modules/google-gax/node_modules/google-auth-library/build/src/auth/googleauth").JSONClient>'.
    Types have separate declarations of a private property 'checkIsGCE'.

Environment details

  • OS: Windows
  • Node.js version: v16.14.2
  • npm version: v8.7.0
  • google-auth-library version: v8.0.1

Steps to reproduce

  1. Use the same code as previously
import { google } from 'googleapis'
import { GoogleAuth } from 'google-auth-library'

function setCredentials(): void {
  const client = new GoogleAuth({
    scopes: ['https://www.googleapis.com/auth/cloud-billing', 'https://www.googleapis.com/auth/cloud-platform'],
  })

  google.options({
    auth: client, // Error is emmitted for this line after updating google-auth-library-nodejs to v8
  })
}
  1. Execute tsc for Typescript compile
@sceee sceee added priority: p2 Moderately-important priority. Fix may not be included in next release. type: bug Error or flaw in code with unintended results or allowing sub-optimal usage patterns. labels Apr 28, 2022
@sceee sceee changed the title GoogleAuth can no longer be used with google-auth-library: Type 'GoogleAuth<JSONClient>' is not assignable to type 'string | OAuth2Client | BaseExternalAccountClient | GoogleAuth<JSONClient> | undefined' GoogleAuth can no longer be used with googleapis: Type 'GoogleAuth<JSONClient>' is not assignable to type 'string | OAuth2Client | BaseExternalAccountClient | GoogleAuth<JSONClient> | undefined' Apr 28, 2022
@danielbankhead danielbankhead self-assigned this Jun 18, 2022
@danielbankhead
Copy link
Contributor

Hey @sceee, I believe this was a temporary issue due to google-auth-library being a different major version from what googleapis required (thus GoogleAuth<JSONClient> != GoogleAuth<JSONClient>).

Closing as this cannot be reproduced.

@LearningLadoo
Copy link

I'm also getting same issue? can you please guide me?

@danielbankhead
Copy link
Contributor

@LearningLadoo this can usually be solved when all dependent libraries are up-to-date.

@LearningLadoo
Copy link

Thank you, my google-auth-library was not updated.

@MrBrax
Copy link

MrBrax commented Oct 25, 2022

agreed, seems completely broken right now

@danielbankhead
Copy link
Contributor

@MrBrax is Auth and it’s dependencies up-to-date?

@MrBrax
Copy link

MrBrax commented Oct 25, 2022

@MrBrax is Auth and it’s dependencies up-to-date?

in the end it seemed that version 6 and 8 of auth was not compatible with the most recent youtube api package (6.0.0), but instead only 7.14.1 worked

@Chris112
Copy link

I had this issue a few months back using the latest versions of @googleapis/drive and @googleapis/gmail and the JWT client from google-auth-library.

The first solution I found was to look at the version of googleapis-common used in the package.json then check the version of google-auth-library it depends on then check the package.json for the version of google-auth-library that it depends on and downgrade to that (v7.14.1)

The even easier solution was to drop google-auth-library and refactor to use the auth client that @googleapis/drive comes with which is google-auth-library internally anyway.

@MrBrax
Copy link

MrBrax commented Oct 25, 2022

yup i hovered over the error (something about oauth2client not being compatible) and it said 7.14.1 in the bundled version so that's what i chose to downgrade to

@danielbankhead
Copy link
Contributor

@MrBrax All of our clients should be using auth V8 by now. What are the exact Google package(s) & versions are you using?

@MrBrax
Copy link

MrBrax commented Oct 25, 2022

@MrBrax All of our clients should be using auth V8 by now. What are the exact Google package(s) & versions are you using?

i was using [email protected] and @googleapis/[email protected] which broke compatibility

@danielbankhead
Copy link
Contributor

That's strange; @googleapis/[email protected] depends on googleapis-common, which depends on google-auth-library v8. What happens if you removed node_modules and do a clean install?

@MrBrax
Copy link

MrBrax commented Oct 25, 2022

That's strange; @googleapis/[email protected] depends on googleapis-common, which depends on google-auth-library v8. What happens if you removed node_modules and do a clean install?

I don't use node_modules but yarn 3 pnp, googleapis-common is at version 5.1.0

@danielbankhead
Copy link
Contributor

Looking a little closer, I see we have a publishing issue - @googleapis/youtube is a bit out of date on the registry:
https://github.com/googleapis/google-api-nodejs-client/blob/main/src/apis/youtube/package.json

I'll sync with the team and get this resolved for you.

@danielbankhead
Copy link
Contributor

@MrBrax Hey! Circling back, we've fixed the publishing issue and @googleapis/youtube is up-to-date with the latest Auth client.

@MrBrax
Copy link

MrBrax commented Nov 7, 2022

Nice!

@jatinsaini66
Copy link

Hey @sceee, I believe this was a temporary issue due to google-auth-library being a different major version from what googleapis required (thus GoogleAuth<JSONClient> != GoogleAuth<JSONClient>).

Closing as this cannot be reproduced.

Can you please give me the steps, so that I can fix that?

@danielbankhead
Copy link
Contributor

@jatinsaini66 you can run npm ls google-auth-library to see which libraries are requiring the different auth version(s). From there you can npm outdated/npm update or npm i $library newer versions of the outdated libraries.

@Viacheslav-Chopyk
Copy link

hey @sceee i have problem with google-auth-library. Can you help?
image

@sceee
Copy link
Author

sceee commented Apr 14, 2023

@chopyk89 looks like you are having a typo in clientId.

@Viacheslav-Chopyk
Copy link

@sceee when I create OAuth 2.0 Client IDs I was given JSON where all parameters are specified. This JSON has a field
"client_id":"168755252870-bu0tubc899hecc1j4dj8cthars57ftc0.apps.googleusercontent.com".
I took it from there
image

@Viacheslav-Chopyk
Copy link

@sceee or I do, something is wrong))

@sceee
Copy link
Author

sceee commented Apr 15, 2023

@chopyk89 take a look at the docs here https://googleapis.dev/nodejs/google-auth-library/8.7.0/ .
It depends on what you want to do and I can just guess.
If you are using Application Default Credentials, I think you don't have to provide a clientId at all.

If you manually want to create an OAuth2Client, that's where you hand in the clientId.

@goodbomb
Copy link

goodbomb commented May 3, 2023

I'm running into the same issue with the Google Drive API.

"@googleapis/drive": "5.1.0",
"google-auth-library": "8.8.0"

Both are at their latest versions, but I'm getting this typescript error:

Type 'BaseExternalAccountClient | ExternalAccountAuthorizedUserClient | OAuth2Client' is not assignable to type 'OAuth2Client'.

@danielbankhead
Copy link
Contributor

@goodbomb

"@googleapis/drive": "5.1.0",
"google-auth-library": "8.8.0"

I'm not sure how this is possible as @googleapis/drive v5.1.0 requires googleapis-common ^6.0.3, which requires google-auth-library "^8.0.2".

Could you double-check your installation?

@goodbomb
Copy link

goodbomb commented May 4, 2023

Hi @danielbankhead, I'm not sure what to tell you. I've deleted node_modules and reinstalled all of my dependencies with those versions set. This is what my package.json deps section looks like (everything should be at its latest version since I'm starting a new project):

  "dependencies": {
    "@google-cloud/local-auth": "2.1.1",
    "@googleapis/drive": "5.1.0",
    "dotenv": "16.0.3",
    "google-auth-library": "8.8.0"
  },
  "devDependencies": {
    "@babel/core": "7.21.8",
    "@babel/preset-env": "7.21.5",
    "@babel/preset-typescript": "7.21.5",
    "@types/express": "4.17.17",
    "@types/jest": "29.5.1",
    "@types/node": "18.16.3",
    "babel-jest": "29.5.0",
    "jest": "29.5.0",
    "rimraf": "5.0.0",
    "ts-node-dev": "2.0.0",
    "typescript": "5.0.4"
  }

And this is the code I'm trying to run (most of which is taken directly from google's own docs at https://developers.google.com/drive/api/quickstart/nodejs but I'm just adding the typescript types):

import { drive, drive_v3 } from '@googleapis/drive';
import { JSONClient } from 'google-auth-library/build/src/auth/googleauth';
import { OAuth2Client } from 'google-auth-library';

// excluded the other code, which is all from that quickstart guide

export async function authorize() {
  let client: JSONClient | OAuth2Client | null = await loadSavedCredentialsIfExist(); // <-- the typing here seemed sketchy
  if (client) {
    return client;
  }
  client = await authenticate({
    scopes: SCOPES,
    keyfilePath: CREDENTIALS_PATH,
  });
  if (client!.credentials) {
    await saveCredentials(client);
  }
  return client;
}

export async function listFilesAndFolders() {
  // create a new Google Drive client
  const client: OAuth2Client = await authorize();   // <-- this is where that type error is happening

  try {
    const rootFolderId = 'YOUR_ROOT_FOLDER_ID_HERE';
    await listFolders(rootFolderId, client);
    await listFiles(rootFolderId, client);
  } catch (err) {
    console.error('Error listing folders and files', err);
  }
}

Here's a screenshot of the error in VSCode:
image

@danielbankhead
Copy link
Contributor

@goodbomb this error is correct as your method, authorize(), can return JSONClient | OAuth2Client.

@goodbomb
Copy link

goodbomb commented May 4, 2023

@danielbankhead Maybe I'm just ignorant to how TypeScript works, but how does one properly type that method based on the nodeJS example provided by Google? That authorize() method is lifted directly from the Quick Start guide.

If I remove the JSONClient type from that client variable, I get this error:

image

/**
 * Reads previously authorized credentials from the save file.
 *
 * @return {Promise<OAuth2Client|null>}
 */
async function loadSavedCredentialsIfExist() {
  try {
    const content = await fs.readFile(TOKEN_PATH);
    const credentials = JSON.parse(content);
    return google.auth.fromJSON(credentials); // this is supposed to return an OAuth2Client
  } catch (err) {
    return null;
  }
}

// This is the original untyped function taken directly from the Quick Start guide
async function authorize() {
  let client = await loadSavedCredentialsIfExist();
  if (client) {
    return client;
  }
  client = await authenticate({
    scopes: SCOPES,
    keyfilePath: CREDENTIALS_PATH,
  });
  if (client.credentials) {
    await saveCredentials(client);
  }
  return client;
}

@goodbomb
Copy link

goodbomb commented May 4, 2023

Is it as simple as casting the return?

async function loadSavedCredentialsIfExist() {
  try {
    const content = await fs.readFile(TOKEN_PATH);
    const credentials = JSON.parse(content.toString());
    return auth.fromJSON(credentials) as OAuth2Client; // this gets rid of the error, but is that legit?
  } catch (err) {
    return null;
  }
}

@danielbankhead
Copy link
Contributor

@goodbomb in the JS sample we know given the context and usage, loadSavedCredentialsIfExist can only be OAuth2Client. TS doesn't have this context and only knows it's a JSONClient (which can be a number of clients). We have a few options for telling TS that this is definitely a particular type:

Personally, I like instanceof and in narrowing rather than as, e.g.:

const client = auth.fromJSON(credentials)
if ("refreshAccessToken" in client) {
  return client; // this is definitely an `OAuth2Client`
}

@goodbomb
Copy link

goodbomb commented May 4, 2023

Thanks a lot @danielbankhead! Much appreciated!

@yogeshwar-chaudhari-20
Copy link

I came across a similar issue while working with Google's play integrity API

If you are importing the required API using the individual module and If you set the auth for the parent Google import using the options method, you get Error: Log in required during the actual API call.

However, for play integrity API at least, it had a provision to pass the auth to the generator function. Check if similar options params are available for API you are working with.

import { playintegrity, type playintegrity_v1 } from '@googleapis/playintegrity';
import { JWT } from 'google-auth-library';

const jwtClient = new JWT({
  email: <client email>,
  key: <private key>
  scopes: [<scope urls>],
});

const playintegrityInstance = playintegrity({ version: 'v1', auth: jwtClient });

instead of

const auth = new google.auth.GoogleAuth({
    // Scopes can be specified either as an array or as a single, space-delimited string.
    scopes: ['https://www.googleapis.com/auth/playintegrity'],
});

// Acquire an auth client, and bind it to all future calls
const authClient = await auth.getClient();
google.options({auth: authClient});  // This emits error

@ccmoralesj
Copy link

ccmoralesj commented Jul 28, 2023

I have everything up to date and I still get the error

No overload matches this call.
  The last overload gave the following error.
    Type 'GoogleAuth<JSONClient>' is not assignable to type 'string | BaseExternalAccountClient | GoogleAuth<JSONClient> | OAuth2Client'.

Here's my code

import { GoogleAuth } from 'google-auth-library'
import { getGoogleCredentialsJSON } from "../../helpers/googleCredentials.js"
import { JSONClient } from 'google-auth-library/build/src/auth/googleauth.js'

export async function generateGoogleClient (): Promise<GoogleAuth<JSONClient>> {
  const googleCredentialsJSON = await getGoogleCredentialsJSON()
  const googleJSONClient = new GoogleAuth({
    scopes: ['https://www.googleapis.com/auth/drive'],
    credentials: googleCredentialsJSON
  })
  return googleJSONClient
}

Here my package.json's dependencies

"dependencies": {
    "@types/koa": "2.13.6",
    "concurrently": "8.2.0",
    "fast-safe-stringify": "2.1.1",
    "google-auth-library": "9.0.0",
    "googleapis": "123.0.0",
    "koa": "2.14.2",
    "koa-parser": "1.0.8",
    "koa-router": "12.0.0",
    "rimraf": "5.0.1",
    "winston": "3.10.0"
  },

@danielbankhead
Copy link
Contributor

@ccmoralesj It sounds like you have multiple versions of auth. Consider running npm ls google-auth-library to verify and to resolve.

We may switch to a capabilities-based model for auth in the future (e.g. requiring an interface instead of the class instance itself) to avoid this issue.

@ccmoralesj
Copy link

ccmoralesj commented Jul 28, 2023

@ccmoralesj It sounds like you have multiple versions of auth. Consider running npm ls google-auth-library to verify and to resolve.

We may switch to a capabilities-based model for auth in the future (e.g. requiring an interface instead of the class instance itself) to avoid this issue.

image

Apparently, I do have more versions but I didn't install them myself. Maybe the inner dependencies did it. What should I do here?

@danielbankhead
Copy link
Contributor

I would recommend installing v8.9.0 for now (npm i [email protected]) until googleapis and googleapis-common are updated.

@MrBrax
Copy link

MrBrax commented Jul 28, 2023

i had the same issue with the newest youtube api too, the auth library seems to be very picky with the version, 8.9.0 works right now

@danielbankhead
Copy link
Contributor

Opened up PR #1624 to greatly improve the experience when transitioning between different versions of google-auth-library.

@danieltroger
Copy link

My only google dependency (in package.json) is "@googleapis/drive": "^8.0.0", and I'm getting the following error, I don't understand if it's an actual issue with my code or with your package?

TS2322: Type 'JSONClient | Compute' is not assignable to type 'string | BaseExternalAccountClient | GoogleAuth<JSONClient> | OAuth2Client | undefined'.
Type 'ExternalAccountAuthorizedUserClient' is not assignable to type 'string | BaseExternalAccountClient | GoogleAuth<JSONClient> | OAuth2Client | undefined'.
Type 'ExternalAccountAuthorizedUserClient' is missing the following properties from type 'OAuth2Client': certificateCache, certificateExpiry, certificateCacheFormat, refreshTokenPromises, and 23 more.

@danielbankhead
Copy link
Contributor

@danieltroger what’s your output of npm ls google-auth-library?

@danieltroger
Copy link

danieltroger commented Jul 31, 2023

Thanks for the reply!

daniel@mmmmmmmmmm folder % yarn why google-auth-library
└─ googleapis-common@npm:6.0.4
   └─ google-auth-library@npm:8.9.0 (via npm:^8.0.2)

But I think it was something with my code, I did the following change and it fixed the type error

screenshot

Idk what I'm doing tho and if the code still works, but I'll see if it fails in the future (or maybe you know?)

Small feedback: I checked here (because it's linked here) if there was any breaking change in how api should be specified and could not find what I was look for. It seems like you have some auto-generated "breaking change" thing which seems very noisy to someone like me who just wonders how to fix a type error that shows up, maybe it could be improved?
Screenshot 2023-07-31 at 17 12 40

@ccmoralesj
Copy link

I would recommend installing v8.9.0 for now (npm i [email protected]) until googleapis and googleapis-common are updated.

Yup. Works perfect! Thanks

@danielbankhead
Copy link
Contributor

@danieltroger

But I think it was something with my code, I did the following change and it fixed the type error

screenshot

Idk what I'm doing tho and if the code still works, but I'll see if it fails in the future (or maybe you know?)

The former returned an AuthClient while the current change is returning a GoogleAuth instance. The GoogleAuth instance can contain a variety of AuthClients (OAuth2Client, JWT, UserRefreshClient, etc.). In that case, either instance should work.

Small feedback: I checked here (because it's linked here) if there was any breaking change in how api should be specified and could not find what I was look for. It seems like you have some auto-generated "breaking change" thing which seems very noisy to someone like me who just wonders how to fix a type error that shows up, maybe it could be improved?
Screenshot 2023-07-31 at 17 12 40

I will happily pass along this feedback - I think we can improve documentation for bundled packages as well.

@williscool
Copy link

Spent way more time on this than I wanted to so have to share

So trying to change to 8.9.0 didn't work for me at all because my project was already pointed to that :/

So I had to figure this out the hard way. A strategically placed Exclude with the right imports makes everything work

import { google, Auth } from 'googleapis';
import { JSONClient } from 'google-auth-library/build/src/auth/googleauth';
import { Impersonated } from 'google-auth-library';

/**
 * Reads previously authorized credentials from the save file.
 *
 */
async function loadSavedCredentialsIfExist(){
  try {
    const content = await fs.readFile(TOKEN_PATH);
    const credentials = JSON.parse(content.toString());
    return google.auth.fromJSON(credentials) as Exclude<Impersonated, Auth.GoogleAuth<JSONClient>>;
  } catch (err) {
    return null;
  }
}

@unknown
Copy link

unknown commented Oct 11, 2023

@williscool

Spent way more time on this than I wanted to so have to share

So trying to change to 8.9.0 didn't work for me at all because my project was already pointed to that :/

So I had to figure this out the hard way. A strategically placed Exclude with the right imports makes everything work

import { google, Auth } from 'googleapis';
import { JSONClient } from 'google-auth-library/build/src/auth/googleauth';
import { Impersonated } from 'google-auth-library';

/**
 * Reads previously authorized credentials from the save file.
 *
 */
async function loadSavedCredentialsIfExist(){
  try {
    const content = await fs.readFile(TOKEN_PATH);
    const credentials = JSON.parse(content.toString());
    return google.auth.fromJSON(credentials) as Exclude<Impersonated, Auth.GoogleAuth<JSONClient>>;
  } catch (err) {
    return null;
  }
}

After digging through some of the code base, I landed on this snippet that is relatively straightforward and doesn't rely on TypeScript magic.

import fs from "fs/promises";
import { Auth } from "googleapis";

async function loadSavedCredentialsIfExist() {
  try {
    const content = await fs.readFile(TOKEN_PATH, { encoding: "utf-8" });
    const credentials = JSON.parse(content);
    const refreshClient = new Auth.UserRefreshClient();
    refreshClient.fromJSON(credentials);
    return refreshClient;
  } catch (err) {
    return null;
  }
}

@ianawilson
Copy link

This seems to be an issue with googleapis 144: Trying to use OAuth2Client with calendar_v3, I get the following:

error: TS2322 [ERROR]: Type 'OAuth2Client' is not assignable to type 'string | BaseExternalAccountClient | GoogleAuth<JSONClient> | OAuth2Client | undefined'.
  Type 'import("https://esm.sh/v135/[email protected]/build/src/auth/oauth2client.d.ts").OAuth2Client' is not assignable to type 'import("https://esm.sh/v135/[email protected]/build/src/auth/oauth2client.d.ts").OAuth2Client'.
    Types have separate declarations of a private property 'redirectUri'.
        this.sdk = new Google.calendar_v3.Calendar({ auth: client });

I get a version of this error on essentially every version going back to googleapis 133. The version numbers differ, but it seems like they are always out of sync.

@abecks
Copy link

abecks commented Nov 19, 2024

Seeing this error still with the current latest versions of 'google-auth-library' and '@google-analytics/admin'.

"google-auth-library": "^9.15.0",
"@google-analytics/admin": "^7.6.0",

const oAuthClient = new OAuth2Client({
  clientId: process.env.GOOGLE_CLIENTID,
  clientSecret: process.env.GOOGLE_SECRET,
  redirectUri: process.env.GOOGLE_REDIRECT,
})

oAuthClient.setCredentials(tokens)

const auth = new GoogleAuth({ authClient: oAuthClient })

const client = new AnalyticsAdminServiceClient({ auth: auth }) // need to use "auth as any" here to avoid the TS error

Type 'OAuth2Client' is missing the following properties from type 'GoogleAuth': #private, isGCE, jsonContent, cachedCredential, and 35 more.ts(2740)

As an aside, going from oAuthClient -> GoogleAuth -> AnalyticsAdminServiceClient is incredibly verbose and I'm really hoping I find a more concise way to do this in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
priority: p2 Moderately-important priority. Fix may not be included in next release. type: bug Error or flaw in code with unintended results or allowing sub-optimal usage patterns.
Projects
None yet
Development

Successfully merging a pull request may close this issue.