I am trying to understand how the authorization(particular the refresh tokens) working for nodejs Google Drive API.
Here it's the code from https://github.com/google/google-api-nodejs-client.
oauth2Client.credentials = {
access_token: 'ACCESS TOKEN HERE',
refresh_token: 'REFRESH TOKEN HERE'
};
client
.plus.people.get({ userId: 'me' })
.withAuthClient(oauth2Client)
.execute(callback);
General Question:
How does refresh tokens actually work together with access token?
Background:
As what I interpret is that each access token has a limited timespan (~1 hr). So when a user FIRST connect to my server (which the server provides mechanism for user authentication), the server receives limited-life access token and ONE-TIME refresh token. After 1 hour, the access token is expired.
Specific question:
Here comes to the key questions. After the expiration, my server stills send request to the Google Drive Api with the EXPIRED access token and refresh token (Server uses session to store those values). Will this still be able to access the content in Google Drive? What I am guessing is that the nodejs lib + google drive api is SMART enough to detect the access token is expired & refresh token is identified & api replace the expired access token with new access token blindly (like server does not need to do anything; just google drive api). Will the api response the server with a new Access Code?
I need to figure this out because I need to organize my code in Nodejs effectively.
Thanks!
Yes.
The Node.js API client will detect access token errors and automatically refresh the token.
You can see this in the source:
var hasAuthError = res.statusCode == 401 || res.statusCode == 403;
// if there is an auth error, refresh the token
// and make the request again
if (!opt_dontForceRefresh && hasAuthError && credentials.refresh_token) {
// refresh access token and re-request
that.refreshToken_(credentials.refresh_token, function(err, result) {
if (err) {
opt_callback && opt_callback(err, null, null);
} else {
var tokens = result;
tokens.refresh_token = credentials.refresh_token;
that.credentials = tokens;
that.request(opts, opt_callback, true);
}
});
}
Related
I am working on AWS Lambda using node.js. I am using node-salesforce to connect to SF App using OAuth. I am not able to get refresh token after login.
var conn = new sf.Connection({
oauth2 : {
clientId : 'XXXXXXXXXXXXXXXXXXXXXXXXXXX',
clientSecret : 'XXXXXXXXXXXXXXXX',
redirectUri : 'https://localhost/callback'
}
});
conn.login('Username', 'XXXXXXXXX', function(err, userInfo) {
if (err) { return console.error(err); }
console.log(userInfo);
console.log(conn);
});
In the output I am expecting a refresh Token that is coming undefined. I am able to get accessToken which I am using for further operation. Now how do i update access token in case of change of access token.
I have gone through its documentation(https://www.npmjs.com/package/node-salesforce). It has a way in which they have used express.js and redirect to salesforce page for authorisation. Since this is written in lambda so I will not prefer to use express.js here or redirection for authorisation.
My problem is how to get refresh token here. Is there any way to do this. Please let me know if I am doing anything wrong.
In order to get a refresh token, you need to specify that you will be using this accessToken offline. This is typically done via a header, but sometimes done via a URL param.
How do I properly setup Gmail API script that sends emails?
I am about to use this method and I started building my script from this quickstart guide.
Is there alternative way to do this without using OAuth 2 validation? Or a way to validate once for all?
Well, in using Gmail APi with your app, you need to use OAuth 2.0 because all request to the Gmail API must be authorized by an authenticated user. And if you notice the quickstart, there is a step here that you need to create a credentials/Outh client ID to make this API work.
For more information, there is another way to authorize your app with Gmail. You can do it with the help of Google+ Sign-in that provide a "sign-in with Google" authentication method for your app.
While asking for authorization from GMail, OAuth 2.0 gives one access token and one refresh token. To avoid validation every time, store the access token. Use the refresh token to get the new access token after it is expired (access token expires every one hour).
Read about this process here: https://developers.google.com/identity/protocols/OAuth2
I found solution using JWT to authorize OAuth2.
You need to have admin account to create Domain wide delegation service account. Then in Developer console you need to download service key JSON file which you load as credentials.
First fetch all users like this: (here you need to use account with admin directory rights)
const google = require('googleapis');
const gmail = google.gmail('v1');
const directory = google.admin('directory_v1');
const scopes = [
'https://www.googleapis.com/auth/gmail.readonly',
'https://www.googleapis.com/auth/admin.directory.user.readonly'
];
const key = require('./service_key.json');
var authClient = new google.auth.JWT(
key.client_email,
key,
key.private_key,
scopes,
"authorized#mail.com"
);
authClient.authorize(function(err, tokens){
if (err) {
console.log(err);
return;
}
directory.users.list(
{
auth: authClient,
customer: 'my_customer',
maxResults: 250,
orderBy: 'email'
}, (err, resp) => {
if (err) {
console.log(err);
return;
}
console.log(resp);
});
});
Then you need to fetch Thread lists (100 per request (page)). And for each thread object you need to call get method for full thread. When using Gmail API authorize as user you want to fetch emails from. In request as userId use value 'me'.
I have built my first Node.js app that is supposed to be installed on a Shopify store. If you want to see what my actual code looks like (app.js) you can view it here. It's really basic so reading through won't be hard.
I know how to authenticate the installation of the app (following the Shopify instructions) but I don't how to authenticate all subsequent requests using the permanent access token that a successful installation provides me with.
By subsequent requests I'm referring to requests to either render the app or requests to install the app, even though the app is already installed.
Right now, I'm storing the shop's name (which is unique) along with the permanent token that Shopify sends me in my database. But I don't know if that's necessary. If I'm not mistaken, simply using the browser's session will do ? But how do I do that ? And how do I use this token every time a request comes through to check if it is a valid one?
Thank you for any help/suggestions!
The code below is sort of a representation of what my actual code looks like in order to give you an idea of what my issues are :
db.once('open', function(callback)
{
app.get('/', function (req, res)
{
var name = getNameFrom(req);
if (existsInDB(name) && tokenExistsInDBfor(name))
{
res.redirect('/render');
/*
Is checking that the shop (along with a permanent token)
exists in my DB enough ?
Shouldn't I check whether the current request comes with
a token that is equal to the one in my DB ?
What if the token received with this request is different
from the one stored in my DB ?
*/
}
else res.redirect('/auth');
});
app.get('/auth', function (req, res)
{
if (authenticated(req))
{
var token = getPermanentToken();
storeItInDB(nameFrom(req), token);
res.redirect('/render');
/*
aren't I supposed to do anything more
with the token I've received ? send it
back/store it in the browser session as well maybe?
is storing it in the db necessary ?
*/
}
});
app.get('/render', function (req, res)
{
/*
How do I check that this request is coming
from an authorised shop that has the necessary token ?
Simply checking my DB will not do
because there might be some inconsistency correct ?
*/
res.sendFile(*file that will build app on the client*);
});
});
Getting access token from Shopify is once time process.
Save access token and shop's name in your DB, and also generate and save 'auth token' based on some algorithm. Return generated auth token to Client. Make sure client sends this auth token in every request.
Now when client hit your server verify auth token; once verified make call to Shopify API using appropriate 'access token' and shop name.
Authentication flow could be as follows:
Get Access token from Shopify
Generate token(i am refering this as auth token) for the Shopify Shop, refer this
Now save shopify's access token, shopify store name and your generated token into DB
Now send your generated token to client(save it in cookie or local storage)
Validation flow:
Clients hits your server to get data with your auth token
Verify this auth token in your DB, and get access token and shop name for that auth token
Now make calls to Shopify API using this access token and shop name
Hope this method helps
I am working on Nodejs Google Api client Oauth process. I follow what the code example for oauth, https://github.com/google/google-api-nodejs-client/blob/master/examples/oauth2.js.
I have one question. How do I check if the access token is expired and how do I use the refresh token to get another access token again?
To be more specific, let's say get access to google+ user profile, so I use the access token to get user profile:
getAccessToken(oauth2Client, function() {
// retrieve user profile
getUserProfile(client, oauth2Client, 'me', function(err, profile) {
if (err) {
console.log('An error occured', err);
return;
}
console.log(profile.displayName, ':', profile.tagline);
});
});
In addition, in the client side of the application(backbonejs), if I am attempting to use google api JS client to access the google drive api (not google plus), I am not sure if I can use the access token I get from server side of the application (nodejs) or I have to do another OAuth using google api JS client.
Best practice to determine if an access token is expired is to try and use it. Although the bundle returned includes the *expires_in* parameter, indicating the number of seconds until the access token expires, this isn't reliable, since it may be revoked and replaced for other reasons at any time.
The procedure then typically is
Attempt to make the call using the access token
If you get an "unauthorized" response, use the referesh token to get a new access token. If this fails, your permission has been revoked
Attempt to make the call using the new access token again
If you're using the library to do other Google API calls - this will be handled for you automatically.
I'm trying to create a rest api for a service I'm working on.
The service has two parts to it - the website and the mobile client. Basically, the mobile device keeps its location up to date via the api, the website displays the data via the api.
Seeing as my application only targets Android, I'm hoping to use 'Sign in with Google' as the authentication mechanism for both the mobile and website clients.
The API is using Node.js and Express.js. I'm running into trouble when generating new user accounts though. Seeing as I don't want to trust data from the client, my expected sign up process was something like this:
Through the website:
User visits website, hits 'Sign up with Google'.
User accepts the app request to see their Google details.
Website gets a google auth token back, which it sends to the api.
API contacts google with that auth token to get the user details.
API creates a new user in the database along with my own form of access token.
API returns my own access token to the client for future request signing.
Through the Android app:
User downloads the app, runs and hits 'Sign up with Google'.
User accepts authorisation step presented by google.
App gets a token, which it sends to the API.
API contacts google with that auth token to get the user details.
API realises the user exists and registers this new device with that user.
API returns my own access token to the app for future request signing.
I'm running into a lot of trouble here as soon as the token gets to the server though. Every time I use the token generated, I just get an error 'Invalid Credentials'.
Initially I started to use Passport.js, but what I found was this. In the documentation it states setup happens like so:
passport.use(new GoogleStrategy({
returnURL: 'http://www.example.com/auth/google/return',
realm: 'http://www.example.com/'
},
function(identifier, profile, done) {
User.findOrCreate({ openId: identifier }, function(err, user) {
done(err, user);
});
}));
But when I log the contents of 'identifier' it is actually something like
https://www.google.com/accounts/o8/id?id=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
I assume the ID is something unique to me but I can't seem to discover exactly what it is. Furthermore I don't know if it is time-limited or will last forever. As a final problem, I don't even know if I can get that same value when signing up via Android because I don't know where the value comes from. It's not the kind of API access token that I was expecting. When I output the contents of profile, it's just my name and email address - nothing that I can use for contacting the Google API with to verify the user.
The above solution I don't like anyway because it means the server hosting the client site has to make an api request in order to pass the id to the api. Or it sends the id details to the client so that it can pass them on to the api server. Or, the website server puts it into the api database, which is also a bad solution.
So next I figured I would use the javascript library from the Google sign in docs. I have something like this:
Website Client:
<script type="text/javascript">
function createUser(token)
{
$.ajax({
url:"http://api.example.com/user",
dataType: 'jsonp',
data: 'token='+token,
success:function(json){
alert("Success: "+json);
},
error:function(jqXHR, textStatus, errorThrown){
alert("Error "+textStatus+" "+errorThrown);
}
});
}
function signinCallback(authResult)
{
if(authResult['access_token'])
{
document.getElementById('signinButton').setAttribute('style', 'display: none');
alert('RES: '+JSON.stringify(authResult));
createUser(authResult['access_token']);
}
else if(authResult['error'])
{
alert('There was an error: ' + authResult['error']);
}
}
</script>
Node API user handling function:
function(req, res)
{
var callback = req.query.callback;
if(callback == null)
{
res.send("{valid:false}");
}
else
{
var token = req.query.token;
if(token == null)
{
res.send("{valid:false}");
}
else
{
var oauth2Client = new OAuth2Client('xxxxxx', 'xxxxxx', '');
oauth2Client.credentials = {
access_token: token
};
googleapis
.discover('plus', 'v1')
.execute(function(err, client){
if(client == null)
{
console.log("Client is null");
}
else
{
var request1 = client.plus.people.get({ userId: 'me' })
.withApiKey('xxxxxx');
request1.execute(function(err, result){
console.log("Result: " + (err ? err.message : result.displayName));
});
}
});
res.set('Content-Type', 'text/javascript');
res.send(callback+"({ret:'User Test'});");
}
}
}
This works fine on the client side - I see the alert box with my access token and some other details. The trouble is that when I call the google api functions on my api server for getting the user details, I get 'Invalid Credentials' returned. I assume this is because I generated the access token in javascript for a website and I'm using it from somewhere else.
So, that pretty much leaves me out of ideas. Is there an easy way to achieve this that I'm missing? I just want to be able to generate a token from a website and from an Android app that I can use on the server for validating the user's details. The generated token doesn't even need to work on the website or the Android app, just from the api server. The API server can't do the process of directing the user to Google for authorisation though because the user doesn't directly interact with it.