Reputation: 189
I write an example about google api using. Google NodeJS Client library. I have followed the instruction set access_type : 'offline'
, however the object return doesn't contains refresh_token
.
My Code:
var http = require('http');
var express = require('express');
var Session = require('express-session');
var google = require('googleapis');
var plus = google.plus('v1');
var OAuth2 = google.auth.OAuth2;
const ClientId = "251872680446-rvkcvm5mjn1ps32iabf4i2611hcg086e.apps.googleusercontent.com";
const ClientSecret = "F1qG9fFS-QwcrEfZbT8VmUnx";
const RedirectionUrl = "http://localhost:8081/oauthCallback";
var app = express();
app.use(Session({
secret: 'raysources-secret-19890913007',
resave: true,
saveUninitialized: true
}));
function getOAuthClient () {
return new OAuth2(ClientId , ClientSecret, RedirectionUrl);
}
function getAuthUrl () {
var oauth2Client = getOAuthClient();
// generate a url that asks permissions for Google+ and Google Calendar scopes
var scopes = [
'https://www.googleapis.com/auth/plus.me'
];
var url = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: scopes // If you only need one scope you can pass it as string
});
return url;
}
app.use("/oauthCallback", function (req, res) {
var oauth2Client = getOAuthClient();
var session = req.session;
var code = req.query.code;
oauth2Client.getToken(code, function(err, tokens) {
console.log("tokens : ", tokens);
// Now tokens contains an access_token and an optional refresh_token. Save them.
if(!err) {
oauth2Client.setCredentials(tokens);
session["tokens"]=tokens;
res.send(`
<html>
<body>
<h3>Login successful!!</h3>
<a href="/details">Go to details page</a>
<body>
<html>
`);
}
else{
res.send(`
<html>
<body>
<h3>Login failed!!</h3>
</body>
</html>
`);
}
});
});
app.use("/details", function (req, res) {
var oauth2Client = getOAuthClient();
oauth2Client.setCredentials(req.session["tokens"]);
var p = new Promise(function (resolve, reject) {
plus.people.get({ userId: 'me', auth: oauth2Client }, function(err, response) {
console.log("response : " , response);
resolve(response || err);
});
}).then(function (data) {
res.send(`<html><body>
<img src=${data.image.url} />
<h3>Hello ${data.displayName}</h3>
</body>
</html>
`);
})
});
app.use("/", function (req, res) {
var url = getAuthUrl();
res.send(`
<html>
<body>
<h1>Authentication using google oAuth</h1>
<a href=${url}>Login</a>
</body>
</html>
`)
});
var port = 8081;
var server = http.createServer(app);
server.listen(port);
server.on('listening', function () {
console.log(`listening to ${port}`);
});
Upvotes: 4
Views: 1929
Reputation: 45493
The refresh token is only sent once the first time user login to your application after approving the scopes you have specified.
Edit 08/2018 : Using approval_prompt:'force'
no longer works, you need to use prompt:'consent'
(check @Alexander's answer)
If you want to get the refresh token each time user login (even if user has already login before and approved the scopes), you have to specify prompt:'consent'
in Oauth2Client
configuration :
var url = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: scopes,
prompt : 'consent'
});
Note that this will require user to accept the specified scope each time he/she will click on your link to authenticate :
You can also disable manually the application in your account permission settings, this will revoke the application and the user will have to accept the scopes again that will trigger the refresh_token
to be sent the next time you authenticate :
FYI, if you need to use access_token
offline, you have to store the refresh_token
server side, and refresh the access_token with the stored refresh_token
when you receive status 401 from Google API. So, if you store refresh_token
as you should, there is actually no need to use prompt:'consent'
and force user to approve the scopes each time he/she connects to your application.
Upvotes: 5
Reputation: 7832
According the documentation the refresh_token is only returned on the first authorization.
You can remove the permissions manually on: https://myaccount.google.com/permissions
Also you can force the user to see the consent screen again by passing &prompt=consent in the authorization URL, just add this parameter:
var url = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: scopes,
prompt: 'consent'
});
It worked just fine for me :)
Upvotes: 1
Reputation: 117281
In some cases (Web clients mostly) the refresh token is only sent the first time the user is authenticated.
If you go to apps connected to your account remove the app in question. Then try and authenticated again. Check and there should now be a refresh token.
Upvotes: 0