File

src/auth/jwtclient.ts

Extends

OAuth2Client

Implements

IdTokenProvider

Index

Properties
Methods

Constructor

constructor(optionsOrEmail?: string | JWTOptions, keyFile?: string, key?: string, scopes?: string | string[], subject?: string, keyId?: string)
Parameters :
Name Type Optional
optionsOrEmail string | JWTOptions Yes
keyFile string Yes
key string Yes
scopes string | string[] Yes
subject string Yes
keyId string Yes

Properties

Optional additionalClaims
Type : literal type
Optional defaultScopes
Type : string | string[]
Optional defaultServicePath
Type : string
Optional email
Type : string
Optional gtoken
Type : GoogleToken
Optional key
Type : string
Optional keyFile
Type : string
Optional keyId
Type : string
Optional scope
Type : string
Optional scopes
Type : string | string[]
Optional subject
Type : string
Optional useJWTAccessWithScope
Type : boolean
Optional _clientId
Type : string
Inherited from OAuth2Client
Defined in OAuth2Client:426
Optional _clientSecret
Type : string
Inherited from OAuth2Client
Defined in OAuth2Client:429
Optional apiKey
Type : string
Inherited from OAuth2Client
Defined in OAuth2Client:431
eagerRefreshThresholdMillis
Type : number
Inherited from OAuth2Client
Defined in OAuth2Client:435
forceRefreshOnFailure
Type : boolean
Inherited from OAuth2Client
Defined in OAuth2Client:437
Optional projectId
Type : string
Inherited from OAuth2Client
Defined in OAuth2Client:433
Optional refreshHandler
Type : GetRefreshHandlerCallback
Inherited from OAuth2Client
Defined in OAuth2Client:439

Methods

authorize
authorize()

Get the initial access token using gToken.

Promise that resolves with credentials

authorize
authorize(callback: (err: Error | null,result: Credentials) => void)
Parameters :
Name Type Optional
callback function No
Returns : void
authorize
authorize(callback?: (err?: Error | null,result?: Credentials) => void)
Parameters :
Name Type Optional
callback function Yes
Returns : Promise | void
createScoped
createScoped(scopes?: string | string[])

Creates a copy of the credential with the specified scopes.

Parameters :
Name Type Optional Description
scopes string | string[] Yes

List of requested scopes or a single scope.

Returns : JWT

The cloned instance.

Async fetchIdToken
fetchIdToken(targetAudience: string)

Fetches an ID token.

Parameters :
Name Type Optional Description
targetAudience string No

the audience for the fetched ID token.

Returns : Promise<string>
fromAPIKey
fromAPIKey(apiKey: string)

Creates a JWT credentials instance using an API Key for authentication.

Parameters :
Name Type Optional Description
apiKey string No

The API Key in string form.

Returns : void
fromJSON
fromJSON(json: JWTInput)

Create a JWT credentials instance using the given input options.

Parameters :
Name Type Optional Description
json JWTInput No

The input object.

Returns : void
fromStream
fromStream(inputStream: stream.Readable)

Create a JWT credentials instance using the given input stream.

Parameters :
Name Type Optional Description
inputStream stream.Readable No

The input stream.

Returns : Promise<void>
fromStream
fromStream(inputStream: stream.Readable, callback: (err: Error | null) => void)
Parameters :
Name Type Optional
inputStream stream.Readable No
callback function No
Returns : void
fromStream
fromStream(inputStream: stream.Readable, callback?: (err?: Error | null) => void)
Parameters :
Name Type Optional
inputStream stream.Readable No
callback function Yes
Returns : void | Promise
Async getCredentials
getCredentials()

Using the key or keyFile on the JWT client, obtain an object that contains the key and the client email.

generateAuthUrl
generateAuthUrl(opts: GenerateAuthUrlOpts)
Inherited from OAuth2Client
Defined in OAuth2Client:533

Generates URL for consent page landing.

Parameters :
Name Type Optional Default value Description
opts GenerateAuthUrlOpts No {}

Options.

Returns : string

URL to consent page.

generateCodeVerifier
generateCodeVerifier()
Inherited from OAuth2Client
Defined in OAuth2Client:554
Returns : void
Async generateCodeVerifierAsync
generateCodeVerifierAsync()
Inherited from OAuth2Client
Defined in OAuth2Client:570

Convenience method to automatically generate a code_verifier, and its resulting SHA256. If used, this must be paired with a S256 code_challenge_method.

For a full example see: https://github.com/googleapis/google-auth-library-nodejs/blob/main/samples/oauth2-codeVerifier.js

getAccessToken
getAccessToken()
Inherited from OAuth2Client
Defined in OAuth2Client:742

Get a non-expired access token, after refreshing if necessary

Returns : Promise<GetAccessTokenResponse>
getFederatedSignonCerts
getFederatedSignonCerts()
Inherited from OAuth2Client
Defined in OAuth2Client:1116

Gets federated sign-on certificates to use for verifying identity tokens. Returns certs as array structure, where keys are key ids, and values are certificates in either PEM or JWK format.

Async getFederatedSignonCertsAsync
getFederatedSignonCertsAsync()
Inherited from OAuth2Client
Defined in OAuth2Client:1131
getIapPublicKeys
getIapPublicKeys()
Inherited from OAuth2Client
Defined in OAuth2Client:1204

Gets federated sign-on certificates to use for verifying identity tokens. Returns certs as array structure, where keys are key ids, and values are certificates in either PEM or JWK format.

Returns : Promise<IapPublicKeysResponse>
Async getIapPublicKeysAsync
getIapPublicKeysAsync()
Inherited from OAuth2Client
Defined in OAuth2Client:1219
Returns : Promise<IapPublicKeysResponse>
Async getRequestHeaders
getRequestHeaders(url?: string)
Inherited from OAuth2Client
Defined in OAuth2Client:795

The main authentication interface. It takes an optional url which when present is the endpoint being accessed, and returns a Promise which resolves with authorization header fields.

In OAuth2Client, the result has the form: { Authorization: 'Bearer ' }

Parameters :
Name Type Optional Description
url string Yes

The optional url being authorized

Returns : Promise<Headers>
Static getRevokeTokenUrl
getRevokeTokenUrl(token: string)
Inherited from OAuth2Client
Defined in OAuth2Client:870

Generates an URL to revoke the given token.

Parameters :
Name Type Optional Description
token string No

The existing token to be revoked.

Returns : string
getToken
getToken(code: string)
Inherited from OAuth2Client
Defined in OAuth2Client:599

Gets the access token for the given code.

Parameters :
Name Type Optional Description
code string No

The authorization code.

Returns : Promise<GetTokenResponse>
Async getTokenInfo
getTokenInfo(accessToken: string)
Inherited from OAuth2Client
Defined in OAuth2Client:1089

Obtains information about the provisioned access token. Especially useful if you want to check the scopes that were provisioned to a given token.

user info.

Parameters :
Name Type Optional Description
accessToken string No

Required. The Access Token for which you want to get user info.

Returns : Promise<TokenInfo>
refreshAccessToken
refreshAccessToken()
Inherited from OAuth2Client
Defined in OAuth2Client:714

Retrieves the access token using refresh token

Returns : Promise<RefreshAccessTokenResponse>
request
request(opts: GaxiosOptions)
Inherited from OAuth2Client
Defined in OAuth2Client:938
Type parameters :
  • T

Provides a request implementation with OAuth 2.0 flow. If credentials have a refresh_token, in cases of HTTP 401 and 403 responses, it automatically asks for a new access token and replays the unsuccessful request.

Parameters :
Name Type Optional Description
opts GaxiosOptions No

Request options.

Returns : GaxiosPromise<T>

Request object

revokeCredentials
revokeCredentials()
Inherited from OAuth2Client
Defined in OAuth2Client:906

Revokes access token and clears the credentials object

Returns : GaxiosPromise<RevokeCredentialsResult>
revokeToken
revokeToken(token: string)
Inherited from OAuth2Client
Defined in OAuth2Client:880

Revokes the access given to token.

Parameters :
Name Type Optional Description
token string No

The existing token to be revoked.

Returns : GaxiosPromise<RevokeCredentialsResult>
verifyIdToken
verifyIdToken(options: VerifyIdTokenOptions)
Inherited from OAuth2Client
Defined in OAuth2Client:1039

Verify id token is token by checking the certs and audience

Parameters :
Name Type Optional Description
options VerifyIdTokenOptions No

that contains all options.

verifySignedJwtWithCerts
verifySignedJwtWithCerts()
Inherited from OAuth2Client
Defined in OAuth2Client:1236
Returns : void
Async verifySignedJwtWithCertsAsync
verifySignedJwtWithCertsAsync(jwt: string, certs: Certificates | PublicKeys, requiredAudience?: string | string[], issuers?: string[], maxExpiry?: number)
Inherited from OAuth2Client
Defined in OAuth2Client:1254

Verify the id token is signed with the correct certificate and is from the correct audience.

Parameters :
Name Type Optional Description
jwt string No

The jwt to verify (The ID Token in this case).

certs Certificates | PublicKeys No

The array of certs to test the jwt against.

requiredAudience string | string[] Yes

The audience to test the jwt against.

issuers string[] Yes

The allowed issuers of the jwt (Optional).

maxExpiry number Yes

The max expiry the certificate can be (Optional).

Returns : unknown

Returns a promise resolving to LoginTicket on verification.

import {GoogleToken} from 'gtoken';
import * as stream from 'stream';

import {CredentialBody, Credentials, JWTInput} from './credentials';
import {IdTokenProvider} from './idtokenclient';
import {JWTAccess} from './jwtaccess';
import {
  GetTokenResponse,
  OAuth2Client,
  RefreshOptions,
  RequestMetadataResponse,
} from './oauth2client';

export interface JWTOptions extends RefreshOptions {
  email?: string;
  keyFile?: string;
  key?: string;
  keyId?: string;
  scopes?: string | string[];
  subject?: string;
  additionalClaims?: {};
}

export class JWT extends OAuth2Client implements IdTokenProvider {
  email?: string;
  keyFile?: string;
  key?: string;
  keyId?: string;
  defaultScopes?: string | string[];
  scopes?: string | string[];
  scope?: string;
  subject?: string;
  gtoken?: GoogleToken;
  additionalClaims?: {};
  useJWTAccessWithScope?: boolean;
  defaultServicePath?: string;
  private access?: JWTAccess;

  /**
   * JWT service account credentials.
   *
   * Retrieve access token using gtoken.
   *
   * @param email service account email address.
   * @param keyFile path to private key file.
   * @param key value of key
   * @param scopes list of requested scopes or a single scope.
   * @param subject impersonated account's email address.
   * @param key_id the ID of the key
   */
  constructor(options: JWTOptions);
  constructor(
    email?: string,
    keyFile?: string,
    key?: string,
    scopes?: string | string[],
    subject?: string,
    keyId?: string
  );
  constructor(
    optionsOrEmail?: string | JWTOptions,
    keyFile?: string,
    key?: string,
    scopes?: string | string[],
    subject?: string,
    keyId?: string
  ) {
    const opts =
      optionsOrEmail && typeof optionsOrEmail === 'object'
        ? optionsOrEmail
        : {email: optionsOrEmail, keyFile, key, keyId, scopes, subject};
    super({
      eagerRefreshThresholdMillis: opts.eagerRefreshThresholdMillis,
      forceRefreshOnFailure: opts.forceRefreshOnFailure,
    });
    this.email = opts.email;
    this.keyFile = opts.keyFile;
    this.key = opts.key;
    this.keyId = opts.keyId;
    this.scopes = opts.scopes;
    this.subject = opts.subject;
    this.additionalClaims = opts.additionalClaims;
    this.credentials = {refresh_token: 'jwt-placeholder', expiry_date: 1};
  }

  /**
   * Creates a copy of the credential with the specified scopes.
   * @param scopes List of requested scopes or a single scope.
   * @return The cloned instance.
   */
  createScoped(scopes?: string | string[]) {
    return new JWT({
      email: this.email,
      keyFile: this.keyFile,
      key: this.key,
      keyId: this.keyId,
      scopes,
      subject: this.subject,
      additionalClaims: this.additionalClaims,
    });
  }

  /**
   * Obtains the metadata to be sent with the request.
   *
   * @param url the URI being authorized.
   */
  protected async getRequestMetadataAsync(
    url?: string | null
  ): Promise<RequestMetadataResponse> {
    url = this.defaultServicePath ? `https://${this.defaultServicePath}/` : url;
    const useSelfSignedJWT =
      (!this.hasUserScopes() && url) ||
      (this.useJWTAccessWithScope && this.hasAnyScopes());
    if (!this.apiKey && useSelfSignedJWT) {
      if (
        this.additionalClaims &&
        (
          this.additionalClaims as {
            target_audience: string;
          }
        ).target_audience
      ) {
        const {tokens} = await this.refreshToken();
        return {
          headers: this.addSharedMetadataHeaders({
            Authorization: `Bearer ${tokens.id_token}`,
          }),
        };
      } else {
        // no scopes have been set, but a uri has been provided. Use JWTAccess
        // credentials.
        if (!this.access) {
          this.access = new JWTAccess(
            this.email,
            this.key,
            this.keyId,
            this.eagerRefreshThresholdMillis
          );
        }

        let scopes: string | string[] | undefined;
        if (this.hasUserScopes()) {
          scopes = this.scopes;
        } else if (!url) {
          scopes = this.defaultScopes;
        }

        const headers = await this.access.getRequestHeaders(
          url ?? undefined,
          this.additionalClaims,
          // Scopes take precedent over audience for signing,
          // so we only provide them if useJWTAccessWithScope is on
          this.useJWTAccessWithScope ? scopes : undefined
        );

        return {headers: this.addSharedMetadataHeaders(headers)};
      }
    } else if (this.hasAnyScopes() || this.apiKey) {
      return super.getRequestMetadataAsync(url);
    } else {
      // If no audience, apiKey, or scopes are provided, we should not attempt
      // to populate any headers:
      return {headers: {}};
    }
  }

  /**
   * Fetches an ID token.
   * @param targetAudience the audience for the fetched ID token.
   */
  async fetchIdToken(targetAudience: string): Promise<string> {
    // Create a new gToken for fetching an ID token
    const gtoken = new GoogleToken({
      iss: this.email,
      sub: this.subject,
      scope: this.scopes || this.defaultScopes,
      keyFile: this.keyFile,
      key: this.key,
      additionalClaims: {target_audience: targetAudience},
    });
    await gtoken.getToken({
      forceRefresh: true,
    });
    if (!gtoken.idToken) {
      throw new Error('Unknown error: Failed to fetch ID token');
    }
    return gtoken.idToken;
  }

  /**
   * Determine if there are currently scopes available.
   */
  private hasUserScopes() {
    if (!this.scopes) {
      return false;
    }
    return this.scopes.length > 0;
  }

  /**
   * Are there any default or user scopes defined.
   */
  private hasAnyScopes() {
    if (this.scopes && this.scopes.length > 0) return true;
    if (this.defaultScopes && this.defaultScopes.length > 0) return true;
    return false;
  }

  /**
   * Get the initial access token using gToken.
   * @param callback Optional callback.
   * @returns Promise that resolves with credentials
   */
  authorize(): Promise<Credentials>;
  authorize(callback: (err: Error | null, result?: Credentials) => void): void;
  authorize(
    callback?: (err: Error | null, result?: Credentials) => void
  ): Promise<Credentials> | void {
    if (callback) {
      this.authorizeAsync().then(r => callback(null, r), callback);
    } else {
      return this.authorizeAsync();
    }
  }

  private async authorizeAsync(): Promise<Credentials> {
    const result = await this.refreshToken();
    if (!result) {
      throw new Error('No result returned');
    }
    this.credentials = result.tokens;
    this.credentials.refresh_token = 'jwt-placeholder';
    this.key = this.gtoken!.key;
    this.email = this.gtoken!.iss;
    return result.tokens;
  }

  /**
   * Refreshes the access token.
   * @param refreshToken ignored
   * @private
   */
  protected async refreshTokenNoCache(
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    refreshToken?: string | null
  ): Promise<GetTokenResponse> {
    const gtoken = this.createGToken();
    const token = await gtoken.getToken({
      forceRefresh: this.isTokenExpiring(),
    });
    const tokens = {
      access_token: token.access_token,
      token_type: 'Bearer',
      expiry_date: gtoken.expiresAt,
      id_token: gtoken.idToken,
    };
    this.emit('tokens', tokens);
    return {res: null, tokens};
  }

  /**
   * Create a gToken if it doesn't already exist.
   */
  private createGToken(): GoogleToken {
    if (!this.gtoken) {
      this.gtoken = new GoogleToken({
        iss: this.email,
        sub: this.subject,
        scope: this.scopes || this.defaultScopes,
        keyFile: this.keyFile,
        key: this.key,
        additionalClaims: this.additionalClaims,
      });
    }
    return this.gtoken;
  }

  /**
   * Create a JWT credentials instance using the given input options.
   * @param json The input object.
   */
  fromJSON(json: JWTInput): void {
    if (!json) {
      throw new Error(
        'Must pass in a JSON object containing the service account auth settings.'
      );
    }
    if (!json.client_email) {
      throw new Error(
        'The incoming JSON object does not contain a client_email field'
      );
    }
    if (!json.private_key) {
      throw new Error(
        'The incoming JSON object does not contain a private_key field'
      );
    }
    // Extract the relevant information from the json key file.
    this.email = json.client_email;
    this.key = json.private_key;
    this.keyId = json.private_key_id;
    this.projectId = json.project_id;
    this.quotaProjectId = json.quota_project_id;
  }

  /**
   * Create a JWT credentials instance using the given input stream.
   * @param inputStream The input stream.
   * @param callback Optional callback.
   */
  fromStream(inputStream: stream.Readable): Promise<void>;
  fromStream(
    inputStream: stream.Readable,
    callback: (err?: Error | null) => void
  ): void;
  fromStream(
    inputStream: stream.Readable,
    callback?: (err?: Error | null) => void
  ): void | Promise<void> {
    if (callback) {
      this.fromStreamAsync(inputStream).then(() => callback(), callback);
    } else {
      return this.fromStreamAsync(inputStream);
    }
  }

  private fromStreamAsync(inputStream: stream.Readable) {
    return new Promise<void>((resolve, reject) => {
      if (!inputStream) {
        throw new Error(
          'Must pass in a stream containing the service account auth settings.'
        );
      }
      let s = '';
      inputStream
        .setEncoding('utf8')
        .on('error', reject)
        .on('data', chunk => (s += chunk))
        .on('end', () => {
          try {
            const data = JSON.parse(s);
            this.fromJSON(data);
            resolve();
          } catch (e) {
            reject(e);
          }
        });
    });
  }

  /**
   * Creates a JWT credentials instance using an API Key for authentication.
   * @param apiKey The API Key in string form.
   */
  fromAPIKey(apiKey: string): void {
    if (typeof apiKey !== 'string') {
      throw new Error('Must provide an API Key string.');
    }
    this.apiKey = apiKey;
  }

  /**
   * Using the key or keyFile on the JWT client, obtain an object that contains
   * the key and the client email.
   */
  async getCredentials(): Promise<CredentialBody> {
    if (this.key) {
      return {private_key: this.key, client_email: this.email};
    } else if (this.keyFile) {
      const gtoken = this.createGToken();
      const creds = await gtoken.getCredentials(this.keyFile);
      return {private_key: creds.privateKey, client_email: creds.clientEmail};
    }
    throw new Error('A key or a keyFile must be provided to getCredentials.');
  }
}

results matching ""

    No results matching ""