grpc-node icon indicating copy to clipboard operation
grpc-node copied to clipboard

`createFromGoogleCredential` is not compatible with `google-auth-library` 10.x.x

Open valkum opened this issue 5 months ago • 2 comments

Problem description

google-auth-library 10.x adopted and moved forward to node native fetch. Thus they switched from

export interface Headers {
  [index: string]: string;
}

to Headers defined in Node.

createFromGoogleCredential uses the following interface

export interface CurrentOAuth2Client {
    getRequestHeaders: (url?: string) => Promise<{
        [index: string]: string;
    }>;
}

which is incompatible.

Reproduction steps

Try createFromGoogleCredential with a client created with google-auth-library 10.x

Environment

  • OS name, version and architecture: aarch64, MacOS
  • Node version: 21
  • Node installation method: volta
  • If applicable, compiler version [e.g. clang 3.8.0-2ubuntu4]
  • Package name and version "@grpc/grpc-js": "^1.13.0",

Additional context

valkum avatar Aug 05 '25 14:08 valkum

I'm experiencing the same issue.

import grpc from "@grpc/grpc-js"
import { GoogleAuth } from "google-auth-library"

const auth = new GoogleAuth({
  scopes: "https://www.googleapis.com/auth/cloud-platform",
})
const client = await auth.getClient()
const token = await client.getAccessToken()

// type error
const callCredentials = grpc.credentials.createFromGoogleCredential(client)

The full error is

TS2345: Argument of type 'AnyAuthClient' is not assignable to parameter of type 'OAuth2Client'.
  Type 'import("/Users/fabian/projects/brmlabs/brm/node_modules/google-gax/node_modules/google-auth-library/build/src/auth/oauth2client").OAuth2Client' is not assignable to type 'import("/Users/fabian/projects/brmlabs/brm/node_modules/@grpc/grpc-js/build/src/call-credentials").OAuth2Client'.
    Type 'OAuth2Client' is not assignable to type 'CurrentOAuth2Client'.
      The types returned by 'getRequestHeaders(...)' are incompatible between these types.
        Type 'Promise<Headers>' is not assignable to type 'Promise<{ [index: string]: string; }>'.
          Type 'Headers' is not assignable to type '{ [index: string]: string; }'.
            Index signature for type 'string' is missing in type 'Headers'

The versions involved

➜  brm git:(main) ✗ npm ls @grpc/grpc-js
@brm/brm@ /Users/fabian/projects/brmlabs/brm
└─┬ @brm/[email protected] -> ./api
  ├─┬ @google-cloud/[email protected]
  │ └─┬ [email protected]
  │   └── @grpc/[email protected]
  └─┬ @opentelemetry/[email protected]
    ├─┬ @opentelemetry/[email protected]
    │ ├── @grpc/[email protected] deduped
    │ └─┬ @opentelemetry/[email protected]
    │   └── @grpc/[email protected] deduped
    ├─┬ @opentelemetry/[email protected]
    │ └── @grpc/[email protected] deduped
    └─┬ @opentelemetry/[email protected]
      └── @grpc/[email protected] deduped

➜  brm git:(main) ✗ npm ls google-auth-library
@brm/brm@ /Users/fabian/projects/brmlabs/brm
└─┬ @brm/[email protected] -> ./api
  ├─┬ @google-cloud/[email protected]
  │ └─┬ [email protected]
  │   └── [email protected]
  ├─┬ @google-cloud/[email protected]
  │ └── [email protected]
  ├─┬ @googleapis/[email protected]
  │ └─┬ [email protected]
  │   └── [email protected]
  ├─┬ @posthog/[email protected]
  │ └─┬ @google/[email protected]
  │   └── [email protected] deduped
  └── [email protected]

All google libraries and grpc are at the latest at the time of writing. You can see it is combining [email protected] and @grpc/[email protected].

FabianFrank avatar Aug 07 '25 17:08 FabianFrank

The workaround that I am going with for now is to inline the createFromGoogleCredential helper which avoids the type mismatch

  const callCredentials = grpc.credentials.createFromMetadataGenerator((options, callback) => {
    void client.getRequestHeaders(options.service_url).then(
      (headers) => {
        const metadata = new grpc.Metadata()
        for (const [key, value] of headers.entries()) {
          metadata.add(key, value)
        }
        callback(null, metadata)
      },
      (err) => {
        // eslint-disable-next-line no-console
        console.error("Failed to get request headers for OTEL", err)
        callback(err)
      }
    )
  })

FabianFrank avatar Aug 07 '25 18:08 FabianFrank