Refresh token of google api do not work properly in nodejs - node.js

I am using google api nodejs , I try to get data from google Anaytics
var google = require('googleapis');
var OAuth2Client = google.auth.OAuth2;
var CLIENT_ID = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
var CLIENT_SECRET = 'xxxxxxxxxxxxxxxxxxxxxx';
//var REDIRECT_URL = 'http://yieldops.co/oauth2Callback';
var REDIRECT_URL = 'http://localhost:8000/oauth2Callback';
var oauth2Client = new OAuth2Client(CLIENT_ID, CLIENT_SECRET,REDIRECT_URL);
var credentials={}
credentials.expiry_date= "1463514280558",
credentials['refresh_token']="aaaaaaaaa"
credentials['access_token']="aaaaaaaaaaaaaaa"
oauth2Client.setCredentials(credentials)
var gauth = {
'auth': outh2Client,
'ids': 'ga:101' ,
'start-date': '2016-01-01',
'end-date': 'today',
'metrics': 'ga:impressions,ga:sessions,ga:pageviews',
'dimensions': 'ga:date'
}
analytics.data.ga.get(gauth, function (err, gaData) {
console.log("err 1234",err)
console.log("gaData ",gaData)
//console.log("ga",Object.keys(gaData))
})
Note
Now the problem is if access token is not expire then it give me data , and if access token is expire then it gave me 400 error Invalid grant . And if I remove expiry_date from credentials then it gave me error
{ [Error: Invalid Credentials]
code: 401,
errors:
[ { domain: 'global',
reason: 'authError',
message: 'Invalid Credentials',
locationType: 'header',
location: 'Authorization' } ] }

access_token have expire time is 1 hour. You must refresh access_token when it's expired.
oauth2Client.refreshAccessToken(function(err, tokens) {
// your access_token is now refreshed and stored in oauth2Client
// store these new tokens in a safe place (e.g. database)
});
Can you find it here

No need to explicitly refresh token, when access_token expired. Oauth2 Client will refresh token automatically and the request is replayed, provided when you get refresh_token in first authorization, set this refresh_token in OAuth2 client credentials as shown in the following code
const {tokens} = await oauth2Client.getToken(code)
oauth2Client.setCredentials(tokens);
Still, you want to manually refresh the access_token, then use the following code.
oauth2Client.on('tokens', (tokens) => {
if (tokens.refresh_token) {
// store the refresh_token in my database!
console.log(tokens.refresh_token);
}
});
OR
oauth2Client.refreshAccessToken((err, tokens) => {
// your access_token is now refreshed and stored in oauth2Client
// store these new tokens in a safe place (e.g. database)
});
References:
https://github.com/googleapis/google-api-nodejs-client/blob/c00d1892fe70d7ebf934bcebe3e8a5036c62440c/README.md#making-authenticated-requests
https://github.com/googleapis/google-api-nodejs-client/blob/c00d1892fe70d7ebf934bcebe3e8a5036c62440c/README.md#manually-refreshing-access-token
https://github.com/googleapis/google-api-nodejs-client#handling-refresh-tokens

Related

Twitter oAuth using chrome extension

I am working on twitter oauth through chrome extension. I need to get oauth_token to authenticate the user. I am referring to https://developer.twitter.com/en/docs/tutorials/authenticating-with-twitter-api-for-enterprise/oauth1-0a-and-user-access-tokens. Can you guide me to send post request for my oauth token in javascript ?
You can refer to the above link for steps but I need to implement my post request in background.js instead to sending it in postman. I need my ext to create new request for each login, which for create different oauth token for each session.
I want to create a post request with following requirements:
URL-'https://api.twitter.com/oauth/request_token'
query- 'oauth_callback':'oob'
auth- we want to provide consumer key and consumer secret here
headers- 'Content-Type':'application/json'
This is a screenshot of postman. On implementing this, the post request returns oauth token and secret.
Please help me out on this.
import oauth from 'oauth';
const oauthCallback = process.env.FRONTEND_URL;
const CONSUMER_KEY = process.env.CONSUMER_KEY;
const CONSUMER_SECRET = process.env.CONSUMER_SECRET;
const _oauth = new oauth.OAuth(
'https://api.twitter.com/oauth/request_token',
'https://api.twitter.com/oauth/access_token',
CONSUMER_KEY, // consumer key
CONSUMER_SECRET, // consumer secret
'1.0',
oauthCallback,
'HMAC-SHA1',
);
export const getOAuthRequestToken = () => {
return new Promise((resolve, reject) => {
_oauth.getOAuthRequestToken((error, oauth_token, oauth_token_secret,
results) => {
if (error) {
reject(error);
} else {
console.log({ oauth_token, oauth_token_secret, results });
resolve({ oauth_token, oauth_token_secret, results });
}
});
});
};
Try this method in your backend to get the OAuth token and secret. It helped in my case, maybe it can work for you as well.
Use this to install oauth lib
npm i oauth
Refer for more info:
https://javascript.works-hub.com/learn/building-with-twitter-authentication-35ad6

JsonWebTokenError: invalid signature when verifying the jwt token

I'm implementing an web app that contains a chatbot that will remind the user on his upcoming google calendar events. I have successfully generated a jwt token when the user authorizes, but, I'm getting this error "JsonWebTokenError: invalid signature" when I verify the token. I'm still new to these concepts so I would really appreciate any help.
Here is where I signed my token:
let iss = 'GoogleCalender'
let sub = 'example#gmail.com'
let aud = 'xxxxxxxxxxxxxx'
let exp = '24h'
let sighOptions = {
issuer: iss,
subject: sub,
audience: aud,
expiresIn: exp,
algorithm: "RS256"
}
app.get('/landingPage', (req, res) => {
const token = jwt.sign({ user: 'iman' }, privateKey , sighOptions);
res.cookie('token', token,{ httpOnly: true });
res.sendFile(path.join(__dirname, "./landingPage.html"));
});
And here is where I verify the token:
let verifyOptions = {
issuer: iss,
subject: sub,
audience: aud,
maxAge: exp,
algorithms: "RS256"
}
function verifyToken(req,res,next){
const baererHeader = req.headers['authorization']
if(typeof baererHeader !== 'undefined'){
const baerer = baererHeader.split(' ')
const baererToken = baerer[1]
req.token = baererToken
next()
}
else{
res.sendStatus(403)
}
}
app.post('/landingPage',verifyToken, express.json(),(req,res)=>{
token = req.token
jwt.verify(token, publicKey, verifyOptions, (err,authData) =>{
const calendar = google.calendar({version: 'v3' , auth:createConnection()});
const agent = new dfff.WebhookClient({
request : req,
response : res
})
if(err) {
console.log(err)
function welcome(agent){
agent.add("Hi, Im helen, Please log in so i can remind you on your upcoming events")
}
}
else{
function welcome(agent){
agent.add("Hi, I'm Rem. Please click on remind me button if you want to be reminded on your upcoming events!")
} )
});
Is there any thing I'm doing wrong??
It's good that you're using a pair of private and public keys. It's better to use asymmetric signing than symmetric.
In your code I can see that you're sending the JWT token in a httpOnly cookie, but then in the landingPage you read it from the Authorization header. Not sure how is that supposed to work. Are you sure you're sending the right JWT to the /landingPage endpoint?
If you want to use this JWT that you issued yourself to access a user's data in a Google Calendar then it will not work. To access this data you need an access token issued by Google. Have a look at Google's documentation to check how to obtain an access token from them which will allow you to call the calendar API. You can still use the token that you are creating as a way of protecting your own endpoints. So: the user will need your token to be able to call your endpoint, and then a token from Google will be used to call the calendar API.

DocuSign Get JWT Token MEAN Stack

Building a basic application where users can find Service Providers using MEAN Stack, and after negotiations are over, agreements are auto generated and have to be signed by both parties.
Got Stuck on generation of JWT Token for authentication.
Steps I followed are:
Generate a url for obtaining consent from user and pass it to frontend. Users will be redirected and permissions can be granted from there.
var url = "https://account-d.docusign.com/oauth/auth?response_type=code&scope=signature&client_id=42017946-xxxx-xxxx-xxxx-81b0ca97dc9a&redirect_uri=http://localhost:4200/authorization_code/callback";
res.status(200).json({
status: 1,
message: 'Fetched',
value: url
});
After successful redirection with code in URL, API call is made to backend for the generation of JWT token.
Token is generated as follows:
var jwt = require('jsonwebtoken');
var privateKey = fs.readFileSync(require('path').resolve(__dirname, '../../src/environments/docusign'));
const header = {
"alg": "RS256",
"typ": "JWT"
};
const payload = {
iss: '42017946-xxxx-xxxx-a5cd-xxxxxx',
sub: '123456',
iat: Math.floor(+new Date() / 1000),
aud: "account-d.docusign.com",
scope: "signature"
};
var token = jwt.sign(payload, privateKey, { algorithm: 'RS256', header: header });
Private key used above is from docusign admin panel.
iss -> Integration key against my app.
sub -> user id in the drop down of user symbol in admin panel
Obtain the access token
const axios = require('axios');
axios.post('https://account-d.docusign.com/oauth/token',
{
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
assertion: token
})
.then(resposne => {
console.log(response);
})
.catch(err => {
if (err.response) {
console.log(err);
} else if (err.request) {}
else {}
})
But I am constantly getting error: { error: 'invalid_grant', error_description: 'no_valid_keys_or_signatures' }
I would suggest using the node.JS SDK or npm package and using the build-it JWT method to authenticate. The code would look like this:
(click here for GitHub example)
DsJwtAuth.prototype.getToken = async function _getToken() {
// Data used
// dsConfig.dsClientId
// dsConfig.impersonatedUserGuid
// dsConfig.privateKey
// dsConfig.dsOauthServer
const jwtLifeSec = 10 * 60, // requested lifetime for the JWT is 10 min
scopes = "signature", // impersonation scope is implied due to use of JWT grant
dsApi = new docusign.ApiClient();
dsApi.setOAuthBasePath(dsConfig.dsOauthServer.replace('https://', '')); // it should be domain only.
const results = await dsApi.requestJWTUserToken(dsConfig.dsClientId,
dsConfig.impersonatedUserGuid, scopes, rsaKey,
jwtLifeSec);
const expiresAt = moment().add(results.body.expires_in, 's').subtract(tokenReplaceMin, 'm');
this.accessToken = results.body.access_token;
this._tokenExpiration = expiresAt;
return {
accessToken: results.body.access_token,
tokenExpirationTimestamp: expiresAt
};

Getting invalid_request for Youtube Analytics with nodejs library

I am trying to setup nodejs with youtube analytics api. I am currently using a refresh token to try and get access tokens. It works great when using postman but I can't seem to replicate the functionality in nodejs and get a 400: invalid_request with no additional information provided.
Here is my code
var google = require('googleapis');
var OAuth2 = google.auth.OAuth2;
var oAuthClient = new OAuth2();
// Retrieve tokens via token exchange explained above or set them:
oAuthClient.setCredentials({
access_token: "",
refresh_token: process.env["YOUTUBE_ANALYTICS_REFRESHTOKEN"]
});
var youtubeAnalytics = google.youtubeAnalytics({
version: 'v1', auth: oAuthClient
});
var moduleExports = {
retrieveDailyBreakdownViews : function(){
var query = {
ids: 'channel==' + {channelID here},
'start-date': '2017-05-01',
'end-date': '2017-05-02',
metrics: 'views,estimatedMinutesWatched',
dimensions: 'insightPlaybackLocationType',
sort: 'views'
}
youtubeAnalytics.reports.query(query, (error, response) => {
console.log(error);
console.log(response);
});
}
}
module.exports = moduleExports;
Any ideas? If this doesn't work I can just try and build the query through HTTP/REST but I'd prefer to use the SDK.
In order to be able to refresh the access token, you will also need the client_id and client_secret. What's happening under the hood is the following request to refresh the token (referenced here):
POST https://accounts.google.com/o/oauth2/token
{
refresh_token: refresh_token,
client_id: this._clientId,
client_secret: this._clientSecret,
grant_type: 'refresh_token'
}
You'll need to initialize your Oauth2 client with :
var oAuthClient = new OAuth2(
YOUR_CLIENT_ID,
YOUR_CLIENT_SECRET,
YOUR_REDIRECT_URL
);
You'll also need to provide a refresh token that was generated using the same client_id / client_secret if you hardcode the refresh token value
This is what I ended up doing to fix the issue
var google = require('googleapis');
var googleAuth = require('google-auth-library');
var auth = new googleAuth();
var oauth2Client = new auth.OAuth2(process.env["YOUTUBE_CLIENT_ID"],
process.env["YOUTUBE_CLIENT_SECRET"]);
oauth2Client.credentials.refresh_token =
process.env["YOUTUBE_ANALYTICS_REFRESHTOKEN"];
var youtubeAnalytics = google.youtubeAnalytics({
version: 'v1'
});
I then make my calls like this:
youtubeAnalytics.reports.query(query, (error, response) => {})

Firebase 3.0 Tokens : [Error: Invalid claim 'kid' in auth header.]

I'm trying to create JWT tokens in node.js for use with the REST api in firebase, but when I try to use them, I get the error "Error: Invalid claim 'kid' in auth header."
This is my code
http.createServer(function (req, res) {
var payload = {
uid: "bruh"
};
var token = jwt.sign(payload, sact["private_key"], {
algorithm: 'RS256',
issuer: sact["client_email"],
subject: sact["client_email"],
audience: 'https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit',
expiresIn: '3600s',
jwtid: sact["private_key_id"],
header: {
"kid": sact["private_key_id"]
}
});
res.writeHead(200);
res.end("It worked. (" + token + ")");
}).listen(port);
These are my requires
var http = require('http');
var jwt = require('jsonwebtoken');
Please use returnSecureToken: true, with correct Spellings
I hope it will solve the problem of Invalid claim 'kid' in the auth header.
This is an issue because you're generating a Firebase ID token, not an access token for the Firebase REST API.
To generate a REST API token I would use the legacy Firebase Token Generator library which still works perfectly well (but only generates REST tokens, not general purpose access tokens).
Note that your Firebase Database secret is now located under the gear icon in the top left of the console.
So I had this error and I've fixed it. Now here is the solution:
You'll need to retrieve the ID-token using an additional function. Here is the function you can use:
firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then(function(idToken) {
// Send token to your backend via HTTPS
// ...
}).catch(function(error) {
// Handle error
});
I implemented it somewhat like this:
//google OAuth login handler
const googleLoginHandler = () => {
const provider = new firebase.auth.GoogleAuthProvider();
firebase.auth()
.signInWithPopup(provider)
.then((result) => {
/** #type {firebase.auth.OAuthCredential} */
setgoogleAuthStatus(true)
// The signed-in user info.
const userId = result.user.uid;
const displayName = result.user.displayName;
const email = result.user.email;
//This is the function for getting the ID-Token
firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then((idToken) => {
// Send token to your backend via HTTPS
console.log(idToken)
}).catch((error) => {
// Handle error
console.log(error.message)
alert(error.message)
});
console.log(result)
}).catch((error) => {
console.log(error)
// Handle Errors here.
alert(error.message)
})
}
The id token you get by this method can be used to access the firebase real-time database and other firebase services.
check out these links for more details:
https://firebase.google.com/docs/auth/admin/verify-id-tokens#retrieve_id_tokens_on_clients
https://firebase.google.com/docs/database/rest/auth#firebase_id_tokens

Resources