I'm using the API (v1.0.10) in the following way:
var oauth2Client = new OAuth2(getGoogleCredentials().clientId, getGoogleCredentials().secret);
oauth2Client.setCredentials({
access_token: user.services.google.accessToken,
refresh_token: user.services.google.refreshToken
});
calendar.events.list({
calendarId: 'primary',
auth: oauth2Client
}, ...);
When my token is expired I get an HTTP 401 back from the server. However, I'd expect the library to automatically refresh my token and make the request again. It doesn't.
I figured out that a workaround is to add the expiry_date
when calling setCredentials, e.g.
oauth2Client.setCredentials({
access_token: user.services.google.accessToken,
refresh_token: user.services.google.refreshToken,
expiry_date: user.services.google.expiresAt
});
But this isn't mentioned in the docs. I'd expect expiry_date
to be optional and the API to auto refresh the token.
Nope it won't refresh. We did this because when you make a request that requires a media body we can't reliably re-add the media body due to the possibility that the media body is a stream or that the entire body is being piped into the request. Yes, it means you need to add expiry date if one hasn't been added or refresh the token yourself if you know it is expired.
Oh ok, makes sense. Can you add expiry_date to the main docs then?
It's not meant to be set by the user really. Not sure if documenting it is suggested because it may change in the future without warning.
Ok. I still think it's worth mentioning something about the library not taking care of refreshing the token, and how to do it in an example.
This is a good point. I filed #262 for this.
Hi Ryan,
I was looking through the source, and it seems that if you do not supply an access token in the setCredentials, it will automatically renew the access token before making the request. Can you confirm this behavior? I sometimes receive an "invalid_grant" after about 30-60 days from authenticating even though I supplied the offline parameter in the oAuth dance.
Would you recommend doing something like this to prevent getting the invalid_grant parameter?
setAuthTokens = function(accessToken, refreshToken) {
if (refreshToken) {
accessToken = null;
}
this.client.setCredentials({
access_token: accessToken,
refresh_token: refreshToken
});
}
The source code for oauth2client.js does basically say that on a 401 or 403 it will refresh the token and retry?
/**
* 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.
* @param {object} opts Request options.
* @param {function} callback callback.
* @return {Request} Request object
*/
OAuth2Client.prototype.request = function(opts, callback) {
Perhaps the comment should also be removed to avoid confusion?
Oh ya this is wrong. I'll fix it.
On Wednesday, September 10, 2014, joewoodhouse [email protected]
wrote:
The source code for oauth2client.js does basically say that on a 401 or
403 it will refresh the token and retry?/**
- 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.
- @param {object} opts Request options.
- @param {function} callback callback.
- @return {Request} Request object
*/
OAuth2Client.prototype.request = function(opts, callback) {Perhaps the comment should also be removed to avoid confusion?
—
Reply to this email directly or view it on GitHub
https://github.com/google/google-api-nodejs-client/issues/261#issuecomment-55193024
.
So is there any event I can listen and refresh token?
I ran into a similar issue. What works for me is to set expiry_date to true when setting the credentials and I don't have a date availble. This will force a token refresh, you can then store the client's expiry_date after using it.
oauth2Client.setCredentials({
access_token: user.google.accessToken,
refresh_token: user.google.refreshToken,
expiry_date: true
});
As this issue is not closed yet, I thought I'd ask for an update on the matter. As discussed before, the token is not automatically refreshed, when sending both the refresh_token
and the access_token
and as @zoellner suggested, adding expiry_date: true
solves this problem. However, in the documentation (README.md
) it says:
You can start using OAuth2 to authorize and authenticate your requests to Google APIs with the retrieved tokens. If you provide a refresh_token and the access_token has expired, the access_token will be automatically refreshed and the request is replayed.
So you might want to update that.
Spent the last hour debugging my code because of the misleading Readme.md :( You should fix this.
Please update the readme.md. As was pointed out by the last two posters, the readme is wrong. The access_token is NOT automatically refreshed. Thanks above for the tip on expiry_date: true
.
Actually, setting expiry_date: true
is forcing a refresh of the access token on every request, which probably is not what you want.
A better work around is to store the expiry_date
the API is returning and including it in the following requests. That will make the auto-refresh work, while only refreshing the access token when needed (instead of on every request).
Eg, something like:
const oauth2Client = new OAuth2(clientId, secret, redirectUrl);
let tokens = db.getTokens();
let {access_token, refresh_token, expiry_date} = tokens;
oauth2Client.setCredentials({access_token, refresh_token, expiry_date});
let response = await gmail.users.messages.list({ userId: 'me', auth: oauth2Client });
// If a refresh occured, store the new access_token and expiry_date
if (oauth2Client.credentials.id_token) {
console.log('Received new tokens');
db.storeTokens(oauth2Client.credentials);
}
@lirbank refresh token work on sockets? such as socket.io
Hello,
How can i get access_toke and refresh_token ?
Can anyone help me??
My Code is :
var http = new XMLHttpRequest();
var url = "https://accounts.google.com/o/oauth2/revoke/?token=" + token;
//var params = "token=" + token;
http.open("GET", url, true);
//Send the proper header information along with the request
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.onreadystatechange = function () {//Call a function when the state changes.
if (http.readyState == 4 && http.status == 200) {
alert(http.responseText);
}
}
http.withCredentials = true;
http.send(null);
Error getting : - 404.No 'Access-Control-Allow-Origin' header is present on the requested resource.
Can i call the calendar event(insert,update,delete) by authentication token without authorization process?
I clarified in the README.
See https://github.com/google/google-api-nodejs-client/issues/261#issuecomment-233215639 for an example.
@jmdobry where does the initial expiry_date
value come from?
After logging into my web app PassportJs Google Oauth2
oAuth2.setCredentials({
access_tokens: user[0].access_token,
refresh_tokens: user[0].refresh_token,
expiry_date: true
});
plus.people.get({
userId: 'me',
auth: oAuth2
}, function (err, response) {
console.log(err);
res.send(response);
});
I am always receiving an error [Error: No access or refresh token is set.]
Can anyone please help me why the tokens are not set
@aduddella Here's an example of plus.people.get
: https://github.com/google/google-api-nodejs-client/pull/690/files#diff-a88bd7f246f78d9b231774787108751f
@lirbank https://github.com/google/google-api-nodejs-client/issues/261#issuecomment-233215639
In contrast, the readme details the following approach:
oauth2client.on('tokens', (tokens) => {
if (tokens.refresh_token) {
// store the refresh_token in my database!
console.log(tokens.refresh_token);
}
console.log(tokens.access_token);
});
Are both approaches fine, or is one recommended? Does tokens
here include expiry_date
?
Greetings! The event based approach is new, and was added after this post was originally answered :) . Both ways are fine honestly. The nice thing about using the event is that you get notified not only when the refresh_token changes, but also when the access_token is refreshed. The tokens returned here should return the expiry_date.
Cheers for the snappy response! 🍻
@JustinBeckwith is there a better example with using the event based approach? I mean in a fuller context. i.e do i listen to the event before making a request to youtube api for example or something?