Code Monkey home page Code Monkey logo

google-auth-library-nodejs's Issues

Add convenience methods for common use cases

Hello again!

I was wondering if it would be possible to design some convenience wrappers around common uses for this library?

I can't appreciate all the nuances and complexities this library has to support, so I can't comment on all of the use cases that can be simplified. But as an example, I made google-auto-auth to make authing with application default, JSON/p12 keyfile, and credentials JS objects easier: https://github.com/stephenplusplus/google-auto-auth/blob/0bea71c76c46158a4a4911b3f16af35f7a16ae9d/index.js#L81-L92

I'm still not entirely sure I'm using this library's API the right way (#53), but a developer using google-auto-auth is surely going to have an easier time getting started.

Thanks!

Documentation

Hello, I just wanted to check if any documentation has been planned for this module? Something like this is a generally accepted format for docs. Maybe for this module, they can be grouped by auth types?


Default Credentials

This library provides an implementation of application default credentials for Node.js.

...

Example

var GoogleAuth = require('google-auth-library');
// ...

API

auth.getApplicationDefault(callback)

callback.err
  • Type: Error

An error occurred while trying to find the default credentials.

callback.authClient
  • Type: Object
Methods
createScopeRequired
  • Type: Function

If defined, scopes are required.

This is just a skeleton, it can of course be modified to your liking.

Thanks!

Error 'The incoming JSON object does not contain a client_email field' on JSON keys

Lately the Google Developer console has been giving me JSON service account keys with empty client_email and client_id fields. These are being generated at https://github.com/google/google-auth-library-nodejs/blob/71511d08a05253ede89930342ccdf4c48f93bead/lib/auth/jwtaccess.js#L101

Either there is a bug in this library (as in having an expectation that client_email must be present), or there is a bug in the developer console (as in generating a key without the required client_email property), but I will start by opening the bug here.

Here's an excerpt from a key I got today. I have verified that others are also getting keys with empty client_email.

  ..... ----END PRIVATE KEY-----\n",
  "client_email": "",
  "client_id": "",
  "type": "service_account"
}

Add a new credential type, IAMCredential

It is constructed with and holds two fields

  • iam-token
  • iam-authority-selector
    IAMCredential applies these values to requests as a pair HTTP headers (or an equivalents) keys
    • "x-goog-iam-authorization-token"
    • "x-goog-iam-authority-selector"
      respectively

N.B, there is no requirement that an IAMCredential be returned by Application Default Credentials.

Support detection of project ID

RE: googleapis/google-cloud-node#1653

It would be nice if the authClient returned from this module also exported its best guess at the project_id. In the case of service account JSON files, they have the project_id set, so exporting that should be simple. For ADC, it would involve spawning a command:

$ gcloud -q config list core/project --format=json
{
  "core": {
    "project": "grape-spaceship-123"
  }
}

cc @tmatsuo @jmdobry

ADC Support for User Refresh Tokens

The initial implementation of Application Default Credentials is missing one of the 3 credential types: User Refresh Tokens. This is basically the end result of a 3LO flow, and is an important part of the tool integration, as the Cloud SDK writes out this form of credential in the well-known-file location.

The file format to support is this:

{  
  "type": "authorized_user",     
  "client_id": "kflc91.apps.googleusercontent.com",     
  "client_secret": "1/olgReg3YaBQqxm6T",
  "refresh_token": "2/fFAGRNJru1FTz70BzhT3Zg"     
}

The "type" value is to differentiate it from a service account. The other 3 values are needed to get refresh tokens back. This is a common OAuth2 scenario, so there is likely to be an existing object that already supports getting access tokens from these values. This file could be in either the well-known file location or the environment variable location.

For reference, the Java implementation of these features is here:
https://github.com/google/google-auth-library-java/blob/master/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java
https://github.com/google/google-auth-library-java/blob/master/oauth2_http/java/com/google/auth/oauth2/UserCredentials.java

This should be about 3 days of work.

API conventions

Oh boy, it's me again.

I think this library would be easier to fit into a modern Node developer's code if it was a bit easier to use.

Using the example from the readme:

(new GoogleAuth).getApplicationDefault(function(err, authClient) {

It's very rare you find the use of new Something() anymore. OO is still an important tool for structuring the code, but I think an approach like gcloud is better for the end user; basically, use OO internally, but don't require the user to see it. Alias by camelCase (as opposed to UpperCamelCase), and auto-initialize for them:

function GoogleAuth() {
  if (!(this instanceof GoogleAuth)) {
    return new GoogleAuth();
  }
}

module.exports.googleAuth = GoogleAuth;

// for the user:
googleAuth()
// is equivalent to:
new googleAuth()

  if (err === null) {
    // Inject scopes if they have not been injected by the environment
    if (authClient.createScopedRequired && authClient.createScopedRequired()) {

createScopedRequired being a method that may or may not exist is confusing. Can't this always be defined? Or maybe from the docs, it can be declared in what cases scopes are required up front?

** Edit ** Looking at this again, couldn't it just be a bool? If the function is sync, it should just be if (authClient.createScopedRequired) {}

      var scopes = [
        'https://www.googleapis.com/auth/cloud-platform',
        'https://www.googleapis.com/auth/compute'
      ];
      authClient = authClient.createScoped(scopes);
    }

The naming here is a bit confusing -- maybe it's just me. createScopedRequired and createScoped. Maybe this could be scopesRequired and addScopes.

Using addScopes would also avoid the re-assignment of the authClient. The pattern there feels a bit backwards. Get an authClient then get another one from it. It would be great if I could have gotten the authClient right from the start (as mentioned in the last suggestion with docs + requiring docs up front) or modify it so that it's good to go (addScopes).

  // Fetch the access token
    var _ = require(lodash);
    var optionalUri = null;  // optionally specify the URI being authorized
    var reqHeaders = {};
    authClient.getRequestMetadata(optionalUri, function(err, headers)) {
      if (err === null) {
        // Use authorization headers
        reqHeaders = _.merge(allHeaders, headers);
      }
    });

This is a good case for #54 -- if this library should be for the dev who just needs a token so they can talk to the API, it shouldn't be this hard. There should be a "getToken" method and a "extendRequestOptions" or something similar.


These are just some thoughts from the only code example given. I think docs and convenience methods will go a very long way, but in general, more terse naming conventions and a modern, intuitive API will help fill in the blanks.

Thanks for listening!

OAuth2 Refresh Tokens

I have implemented the following process flow:

  1. Try to authorize the client, using this function:
function _authorise(mailBox, callback) {
  let auth = new googleAuth();

  let clientId = eval(`process.env.GMAIL_API_CLIENT_ID_${mailBox.toUpperCase()}`);
  let clientSecret = eval(`process.env.GMAIL_API_CLIENT_SECRET_${mailBox.toUpperCase()}`);
  let redirectUri = eval(`process.env.GMAIL_API_REDIRECT_URI_${mailBox.toUpperCase()}`);
  let tokenFile = process.env.GMAIL_API_TOKEN_PATH + mailBox.toLowerCase()+ process.env.GMAIL_API_TOKEN_BASE_FILE_NAME;

  let oauth2Client = new auth.OAuth2(clientId, clientSecret, redirectUri);
  fs.readFile(tokenFile, ((err, token) => {
    if (err) {
      _getNewToken(mailBox,oauth2Client,callback);
    } else {
      oauth2Client.credentials = JSON.parse(token);
      callback(oauth2Client);
    }
  }))
}
  1. The method will check for existence of a token in a file. If the file is NOT found, the following functions will create the file:
function _getNewToken(mailBox, oauth2Client, callback) {
  var authUrl = oauth2Client.generateAuthUrl({
    access_type: 'offline',
    scope: process.env.GMAIL_API_SCOPES
  });
  console.log('To authorize this app, please use this url: ', authUrl);
  var rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
  });
  rl.question('Enter the code from that page here: ', ((code) => {
    rl.close();
    oauth2Client.getToken(code, function(err, token) {
      if (err) {
        console.log('Error while trying to retrieve access token', err);
        return;
      }
      oauth2Client.credentials = token;
      _storeToken(mailBox,token);
      callback(oauth2Client);
    });
  }));
}

function _storeToken(mailBox, token) {
  let tokenFile = process.env.GMAIL_API_TOKEN_PATH + mailBox.toLowerCase()+ process.env.GMAIL_API_TOKEN_BASE_FILE_NAME;
  fs.writeFile(tokenFile, JSON.stringify(token));
}

i am using https://www.googleapis.com/auth/gmail.readonly as the scopes.

Here's a sample of the file created:

{"access_token":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","token_type":"Bearer","refresh_token":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","expiry_date":1460509994081}

When processed, here's a sample of the auth object that is returned:

OAuth2Client {
  transporter: DefaultTransporter {},
  clientId_: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com',
  clientSecret_: 'xxxxxxxxxxxxxxxxxxxxxxxx',
  redirectUri_: 'urn:ietf:wg:oauth:2.0:oob',
  opts: {},
  credentials: {
access_token: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
     token_type: 'Bearer',
     refresh_token: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
     expiry_date: 1460509994081
  }
}

If I delete the file, and go through the manual consent process, then the authentication works 100%, until the token expires. After this, I get the "Invalid Credentials" message.

My assumption is that once the token expires, that the refresh token should auto recreate the access token. Am I missing something?

Promote OAuth2 service account to Jwt Access credentials

Application Default Credentials can return Oauth2 service account credentials. gRPC can use more efficient JwtAccess credentials in place of this if no scopes have been specified. This tracks logic to detect this case and "promote" the credentials to JwtAccess form with the same identity properties if the OAuth2 form is passed in for use by gRPC.

Logic should be similar to this (in Java):

if (credentials instanceof ServiceAccountOAuth2Credentials) {
ServiceAccountOAuth2Credentials serviceAccount =
(ServiceAccountOAuth2Credentials)credentials;
if (serviceAccount.getScopes().length() == 0) {
credentials = new ServiceAccountJwtAccessCredentials(
serviceAccount.getAccountEmail(),
serviceAccount.getPrivateKey(),
serviceAccount.getPrivateKeyId());
}
}

Request callback function arguments are not in correct order

The callback functions in request module have arguments error, response, body, in that order. But DefaultTransporter passes the arguments in the order error, body, response, in lines 70 and 106

I suppose that's because the API is designed to return meaningful stuff in body of the HTTP response. And that's fine.

The problem arises when someone writes a callback that uses the response argument, and due to the difference is design, naively ends up using body.

low error margin on expiry_date => isTokenExpired false negatives

My app saves refresh tokens in long-term storage and caches the transient access tokens. I make calls to to the google drive api, polling the changes endpoint in ~1 minute intervals.

Every once in a while (~24 hours), I get a 401 Invalid Credentials error. The refresh token is definitely fine - it hasn't expired or been revoked, e.g. using the same refresh token a minute later (on the next poll cycle), it again continues to work again, despite the auth failure in the previous poll cycle.

Because it occurs pretty randomly, I think this issue originates from the following lines in the auth client library:

tokens.expiry_date = ((new Date()).getTime() + (tokens.expires_in * 1000));
var isTokenExpired = expiryDate ? expiryDate <= (new Date()).getTime() : false;

If there's any significant network latency in the remote calls, then the true expiry date will be earlier than the computed expiry_date, and isTokenExpired may be set to false even when it should really be true. This would result in an API call with the expired access token, leading to a 401 Invalid Credentials error.

In my specific case, it would also makes sense in that on the next poll cycle, we would have passed the computed expiry_date, and the refresh token is then used to get a new access token, and the system continues to work fine.

Let me know if I'm totally off base, and thanks for this great client library!

generateAuthUrl doesn't pass state token

Should the generateAuthUrl method from OAuth2Client accept a state param in order to generate an auth url that provides anti-forgery unique session token validation?

The implementation flow suggested by Google (link) uses an auth url with the state param.

Browser support?

I want to use this in the browser via Browserify, but it looks like it depends on process.env. Is there another way to use Application Default Credentials in the browser? I've searched and can't seem to find anything.

Buggy comment in oauth2client.js regarding replay on 401/403

The docstring on OAuth2Client.prototype.request says:

 * 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.

But I don't see any logic that would retry on 401/403, nor does that seem plausible given that it wouldn't work with stream bodies. AFAIK, the token is only refreshed before making the request. (Sorry if I missed something.)

Error code no longer passed through in response

[This is cross-posted from https://github.com/googleapis/google-api-nodejs-client/issues/424. I'm not sure what project it should be in.]

I'm using v2.0.3 of this library in the following way:

      client.users.drafts.update({
        userId: 'me',
        id: gmailDraftId,
        resource: {
          message: {
            raw: require('base64-url').encode(job.data.emailDraft)
          }
        }
      }, function(err, res, req) {
          // Detect 404 errors
         if (err.code === 404) console.log('does not exist');
      }));

In v1.x of this library, err.code was populated and correctly set to 404 when the draft didn't exist. However, since I upgraded to 2.x, err.code is now undefined. However, the response from the api hasn't changed; req.body is still: { error: { errors: [Object], code: 404, message: 'Not Found' } } }.

Did something break in 2.x causing the error code to not get passed through from the response?

Make it easier to use OAuth2Client with multiple processes?

If I have multiple processes working with the same clientId and token, I need to make sure both processes are exactly in sync, knowing about the latest token, and grabbing an exclusive lock before trying to refresh the token. But this use case doesn't seem to be supported in OAuth2Client. For example, the docstrings describe that the request can be retried if it fails due to an expired token, so .credentials could change without me knowing for a while. And there doesn't seem to be an obvious place to insert an exclusive lock to prevent two processes from trying to refresh the token at the same time. The most obvious route seems to be to subclass OAuth2Client, override OAuth2Client.prototype.getRequestMetadata, and reimplement that method to grab the token out of a file and also grab an exclusive lock before trying to refresh. But the method calls the private this.refreshToken_. I could call this.refreshAccessToken instead, but it is deprecated.

Is this the right approach, or should I be looking elsewhere?

If it is, I think some tweaks could make this easier for the user to implement, e.g. if OAuth2Client.prototype.getRequestMetadata called a public overrideable method instead of this.refreshToken_; then I could just override that method instead of getRequestMetadata. I think this.credentials would also need to be replaced with an overrideable method that calls a callback with the latest credentials. That seems like a bigger change.

Jwt Access Credentials should cache JWTs

The JWT Access Credentials should temporarily cache JWTs. Suggested algorithm:

  • Hash JWTs using Audience as key.
  • Also store the timestamp of last use with each JWT.
  • On access clear any JWT unused for more than 1 hour.

0.9.4 Causes error:0906D06C:PEM routines:PEM_read_bio:no start line

Full error is
139661365319552:error:0906D06C:PEM routines:PEM_read_bio:no start line:../deps/openssl/openssl/crypto/pem/pem_lib.c:696:Expecting: ANY PRIVATE KEY

I use google apis node for big query in some of my projects and was wiping my node_modules for anther reason. When I restart my project I got the above error even though my pem key hadn't changed. I got a new pem key but that didn't change the error.

After some investigation I found that the google-auth-library had bumped from 0.9.3 to 0.9.4. Forcing it back to 0.9.3 with my original pem key auths fixed the problem.

Bump Version to remove Security Vulnerability

Can you please publish the latest version of the code to NPM that includes the fix for the security vulnerability in request? It's also causing NPM shrinkwrap to fail due to a bug in NPM if you have a newer version of request required in your library

Getting a 'conflicting engine id' error in JWT module

Hi there

I call the 'authorize' function of the JWT module and get error Error: error:26078067:engine routines:ENGINE_LIST_ADD:conflicting engine id

Full details
I am using a windows 7.1 machine but I am running this under docker, using the iron.io docker image. So in the docker BASH shell I execute command:

$ docker run --rm  -v "//$PWD":/worker -w //worker iron/node:4.1 node index.js

and receive stack trace

Error: error:26078067:engine routines:ENGINE_LIST_ADD:conflicting engine id
    at Error (native)
    at Sign.sign (crypto.js:279:26)
    at Object.sign (/worker/node_modules/jwa/index.js:53:47)
    at Object.jwsSign [as sign] (/worker/node_modules/jws/lib/sign-stream.js:23:
26)
    at GoogleToken._signJWT (/worker/node_modules/gtoken/lib/index.js:238:25)
    at GoogleToken._requestToken (/worker/node_modules/gtoken/lib/index.js:193:8
)
    at GoogleToken.getToken (/worker/node_modules/gtoken/lib/index.js:75:12)
    at /worker/node_modules/google-auth-library/lib/auth/jwtClient.js:137:21
    at JWT._createGToken (/worker/node_modules/google-auth-library/lib/auth/jwtC
lient.js:225:12)
    at JWT.refreshToken_ (/worker/node_modules/google-auth-library/lib/auth/jwtC
lient.js:133:15)

My code:

var jwt = require('google-auth-library/lib/auth/jwtClient');
var key = require('mykeyfile.json');
var jwtClient = new jwt(key.client_email, null, key.private_key, ['https://www.google.com/m8/feeds']); 

jwtClient.authorize(function(err, tokens) {
     if (err) {throw err;}

 console.log ("authorised :-)");
 console.log("token " + tokens.access_token);


 })

Any help much appreciated

Chris

generateAuthUrl() generated url always asks for offline access

the generateAuthUrl() method generatates thee different urls for me, which differs from the access_type parameter

with access_type = 'online':

https://accounts.google.com/o/oauth2/auth?access_type=online&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile&response_type=code...

with access_type = 'offline':

https://accounts.google.com/o/oauth2/auth?access_type=offline&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile&response_type=code...

and without access_type (according to this example it should defaults to online):

https://accounts.google.com/o/oauth2/auth?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile&response_type=code...

Regardless of the url, there is always a prompt asking for offline access.

The version of the library I've used: 0.9.6

The code I've used to generate the url:

var url = oauth2Client.generateAuthUrl({
    access_type: 'online',
    scope: 'https://www.googleapis.com/auth/userinfo.profile'
});

JWT Client: Cannot read property refreshToken_ of undefined

Just noticed a bug in the lib/auth/jwtclient.js in the authorize method:

/**
 * Get the initial access token using gToken.
 * @param {function=} opt_callback Optional callback.
 */
JWT.prototype.authorize = function(opt_callback) {
  var that = this;
  var done = opt_callback || noop;

  that.refreshToken_(null, function(err, result) {
    if (!err) {
      that.credentials = result;
      that.credentials.refresh_token = 'jwt-placeholder';
      that.key = that.gtoken.key;
      that.email = that.gtoken.iss;
    }
    done(err, result);
  });
};

that is undefined!

Use done callback for async tests

This is missing in a couple of places. I have specifically noticed it missing in JWT#fromJSON tests. Those currently work anyway because the callback is called synchronously, but that should not be assumed.

refresh token does not work for jwt client

After a long analysis I found following:

JWT.prototype.refreshToken_ = function(ignored_, opt_callback) {
  this._createGToken(function(err, gToken) {
    if (err) {
      callback(opt_callback, err);
    } else {
      gToken.getToken(function (err, token) {
        callback(opt_callback, err, {
          access_token: token,
          token_type: 'Bearer',
          expiry_date: gToken.token_expires * 1000 // <-- wrong
        });
      });
    }
  });
};

The problem is, the gToken object does not have a 'token_expires' property but a porperty called 'expires_at' which is a timestamp in ms.

The correct code is:

JWT.prototype.refreshToken_ = function(ignored_, opt_callback) {
  this._createGToken(function(err, gToken) {
    if (err) {
      callback(opt_callback, err);
    } else {
      gToken.getToken(function (err, token) {
        callback(opt_callback, err, {
          access_token: token,
          token_type: 'Bearer',
          expiry_date: gToken.expires_at // <-- right
        });
      });
    }
  });
};

I think there is a confusion between the gtoken library and the gapitoken library which has a 'token_expires' property in its token object

JWT access token is created every time you call getRequestMetadata

It looks like the JWT access token auth implementation creates a new JWT access token every time you call getRequestMetadata, instead of reusing a token created previously (if that one is still valid and has the same authUri).

see https://github.com/google/google-auth-library-nodejs/blob/master/lib/auth/jwtaccess.js#L55

This brings two problems:
-- the auth headers will be different every time you make an RPC (issue time will differ so the access token will also be different), and HTTP/2 header compression won't be able to cache the header that is considerably larger in size than a regular OAuth2 token.
-- additional overhead signing the JWT for each request (not sure how much of an issue, but I think I can be a problem under heavy load).

The exact way of caching JWT access tokens needs some thought - it needs to correctly handle token expiration and handle access tokens for different authUris separately.

it would also be good to investigate how do JWT access token implementations in other languages (Ruby, Java, etc.) handle this, I wouldn't be too surprised if they were behaving the same as node.

TypeError: Not a Buffer

When using the verifyIdToken to verify a really old token (So far I only encoutered with these kind of tokens), instead of getting an expired error the app throws this error.

I've digged a bit and found that the main issues resides within the line 495 in oauth2client.js:

var pem = certs[envelope.kid];

That resolves to undefined sometimes. envelope.kid holds a value, but not one that matches the certs generated by the getFederatedSignonCerts function in oauth2client.js, thus causing the pemVerifier.verify throw.

Very pathetic documentation!!

I wanted you to note this point. Thats why I opened this as an issue. A good detailed document will never do any bad. Its really hard to find how to use this. Please update this doc so that users with all levels of experience like novice to professionals can seamlessly use this.

DeprecationWarning: Using Buffer without `new` will soon stop working.

I get a DeprecationWarning when calling the authorize method on google.auth.JWT in node 7.2.0

This is caused by the base64url package inside the jws package, and has been fixed in the latest versions of each. This can be fixed by bumping the jws package from 3.0 to 3.1.

full trace when I use the node flag to throw deprecation warnings:

{ DeprecationWarning: Using Buffer without `new` will soon stop working. Use `new Buffer()`, or preferably `Buffer.from()`, `Buffer.allocUnsafe()` or `Buffer.alloc()` instead. at Buffer (buffer.js:79:13) at base64url (/Users/andrew/Desktop/someproject/node_modules/base64url/index.js:41:21) at jwsSecuredInput (/Users/andrew/Desktop/someproject/node_modules/jws/lib/sign-stream.js:11:25) at Object.jwsSign [as sign] (/Users/andrew/Desktop/someproject/node_modules/jws/lib/sign-stream.js:22:24) at GoogleToken._signJWT (/Users/andrew/Desktop/someproject/node_modules/gtoken/lib/index.js:240:25) at GoogleToken._requestToken (/Users/andrew/Desktop/someproject/node_modules/gtoken/lib/index.js:195:8) at GoogleToken.getToken (/Users/andrew/Desktop/someproject/node_modules/gtoken/lib/index.js:77:12) at /Users/andrew/Desktop/someproject/node_modules/google-auth-library/lib/auth/jwtclient.js:137:21 at JWT._createGToken (/Users/andrew/Desktop/someproject/node_modules/google-auth-library/lib/auth/jwtclient.js:226:12) at JWT.refreshToken_ (/Users/andrew/Desktop/someproject/node_modules/google-auth-library/lib/auth/jwtclient.js:133:15) name: 'DeprecationWarning' }

Simplify surface

The GoogleAuth class would work just as well as a simple module that exposes methods without being instantiated.

JWT client getRequestMetadata should return value

Just spent a short while debugging.

JWT.prototype.getRequestMetadata = function(opt_uri, cb_with_metadata) {
  if (this.createScopedRequired() && opt_uri) {
    // no scopes have been set, but a uri has been provided.  Use JWTAccess credentials.
    var alt = new JWTAccess(this.email, this.key);
    alt.getRequestMetadata(opt_uri, cb_with_metadata);
  } else {
    JWT.super_.prototype.getRequestMetadata.call(
        this, opt_uri, cb_with_metadata);
  }
};

The oauth2client getRequestMetaData returns a value. And if you look at OAuth2Client.prototype.request it will return whatever getRequestMetadata returns. JWT doesn't bubble up the return.

Not returning the value causes issues in https://github.com/google/google-api-nodejs-client/blob/master/lib/apirequest.js where it'll fall over when it tries to pipe the request.

Possible fix, just return the values returned.

JWT.prototype.getRequestMetadata = function(opt_uri, cb_with_metadata) {
  if (this.createScopedRequired() && opt_uri) {
    // no scopes have been set, but a uri has been provided.  Use JWTAccess credentials.
    var alt = new JWTAccess(this.email, this.key);
    return alt.getRequestMetadata(opt_uri, cb_with_metadata);
  } else {
    return JWT.super_.prototype.getRequestMetadata.call(
        this, opt_uri, cb_with_metadata);
  }
};

Brains not functioning 100%, so if anything didn't make sense, let me know

cannot drive.files.update to "addParents" with service jwt client

I have a service account and I'm using the subject param in JWT function from google-auth-library-nodejs/lib/auth/jwtclient.js. I get a 200 OK status but the parents are not actually added.

Example:

const jwtClient = new google.auth.JWT(
        key.client_email,
        null,
        key.private_key,
        [
            'https://www.googleapis.com/auth/spreadsheets',
            'https://www.googleapis.com/auth/drive'
        ],
        '[email protected]'
);

async.waterfall(
    [
        (callback) => {
            sheets.spreadsheets.create(
                {
                    auth: jwtClient,
                    resource: {
                        properties: {
                            title: moment().format('YYYY-MM-DD')
                        }
                    }
                },
                (err, spreadsheet) => {
                    console.log(spreadsheet);
                    callback(err, spreadsheet.spreadsheetId)
                }
            )
        },
        (spreadsheetId, callback) => {
            console.log(config.spreadsheetFolders.international);
            drive.files.update(
                {
                    auth: jwtClient,
                    fileId: spreadsheetId,
                    resource: {
                        addParents: config.spreadsheetFolders.international
                    }
                },
                (err, file) => {
                    console.log(file);
                    callback(err, file);
                }
            )
        }
    ],
    (err, results) => {
        if (err) {
            console.log(err);
        } else {
                        something();
        }
    }
);

Ideas? This is Drive api v3 just fyi.

OAuth2.getAccessToken returns invalid accessToken if refreshed

If the token has expired and you have a refresh token setup, it returns a new access token that only has two parts, i.e. accessToken.split('.').length === 2, which results in a JSON parse error when doing:

let split = accessToken.split('.');
let payloadSegment = split[1];
payload = JSON.parse(oauth.decodeBase64(payloadSegment));

So in the getAccessToken method, the tokens that are returned seem to have an id_token which looks more like an accessToken, but that's not accessible since those are returned so I wrote my own version of that method that returns all the tokens.

/**
 * Copy of getAccessToken, but returning all of the tokens
 */
google.auth.OAuth2.prototype.getOrRefreshTokens = function(callback) {
  var credentials = this.credentials;
  var expiryDate = credentials.expiry_date;

  // if no expiry time, assume it's not expired
  var isTokenExpired = expiryDate ? expiryDate <= (new Date()).getTime() : false;

  if (!credentials.access_token && !credentials.refresh_token) {
    return callback(new Error('No access or refresh token is set.'), null);
  }

  var shouldRefresh = !credentials.access_token || isTokenExpired;
  if (shouldRefresh && credentials.refresh_token) {
    if (!this.credentials.refresh_token) {
      return callback(new Error('No refresh token is set.'), null);
    }

    this.refreshAccessToken(function(err, tokens, response) {
      if (err) {
        return callback(err, null, response);
      }     
      if (!tokens || (tokens && !tokens.access_token)) {
        return callback(new Error('Could not refresh access token.'), null, response);
      }     
      return callback(null, tokens, response);
    });   
  } else {
    return callback(null, credentials, null);
  }
};

I guess it's possible that I'm using the wrong token, and the access/id tokens need to be used differently? Which token does what and should be used for what purpose?

Add a public method to retrieve the access token to OAuth2Client

I need this because I have a library that needs to use the access token to set HTTP2 headers, without routing any requests through the Auth library.

I think that this can be accomplished by moving the authorize function, or a very similar implementation, from jwtclient.js to oauth2client.js.

Add owners to the npm package

Can we add some new owners to the npm package?

npm owner add jmdobry
npm owner add murgatroid99
npm owner add stephenplusplus

Fix lint errors

All of the travis builds are failing with dozens of lint errors, which makes it hard to tell if the tests are actually passing. This should be fixed.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.