Google Cloud Function + Calendar API - javascript

I'm trying to use a Google Cloud Function to handle authorization for the google calendar api. But I'm having trouble exchanging the code for a token. I have written two functions, one that generates an auth url that directs users to sign in, with a code and the second is the one that should exchange the code for a token and redirect users to the page. The second function just times out and doesn't return anything.
// The first cloud function
const { google } = require('googleapis');
const credentials = require('./credentials.json')
exports.getURL = async (req, res) => {
const SCOPES = ["https://www.googleapis.com/auth/calendar.readonly"];
let redirectURL, oAuth2Client, response;
try {
redirectURL = await authorize(credentials);
}
catch (e) {
// console.log(e.message);
response = JSON.stringify({
statusCode: 500,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': 'true',
},
body: JSON.stringify({
error: e.message,
}),
})
return res.send(response);
}
console.log(redirectURL);
response = {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': 'true',
'Cache-Control': 'no-cache',
'Content-Type': 'text/html',
},
body: redirectURL,
}
return res.send(response);
function authorize(credentials) {
// const { CLIENT_SECRET, CLIENT_ID, REDIRECT_URIS } = process.env
const {client_secret, client_id, redirect_uris} = credentials.installed
oAuth2Client = new google.auth.OAuth2(
client_id,
client_secret,
redirect_uris[0]
);
return getAccessToken(oAuth2Client);
}
function getAccessToken(oAuth2Client) {
const authUrl = oAuth2Client.generateAuthUrl({
access_type: "offline",
scope: SCOPES,
});
// returns link that user clicks to authorize app
return authUrl;
}
}
The output of the first function is this:
{
"statusCode": 200,
"headers": {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Credentials": "true",
"Cache-Control": "no-cache",
"Content-Type": "text/html"
},
"body": "https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcalendar.readonly&response_type=code&client_id=92706390722-rl3h6c2cmqqi15m0ou58cva56hp2vo0c.apps.googleusercontent.com&redirect_uri=https%3A%2F%2Fus-central1-learning-node-291903.cloudfunctions.net%2FgetCalEvents"
}
I'm not sure what is happening, but the console log statements, don't output anything useful. Any hints as to where I could be encountering a problem?
// 2nd function that exchanges code for token
exports.getCalEvents = async (req, res) => {
// wait for an event
// request comes in with code parameter and query string from 'GET' request
let params = req.query;
const code = params.code;
let token, response;
try {
token = await getAccessToken(code);
console.log('token', token);
} catch (err) {
response = JSON.stringify({
statusCode: 500,
})
return response;
}
async function getAccessToken(code) {
console.log(code);
const {client_secret, client_id, redirect_uris} = credentials.installed;
oAuth2Client = new google.auth.OAuth2(
client_id,
client_secret,
redirect_uris[2]
);
try {
let accessToken = await oAuth2Client.getToken(code);
console.log('access token', accessToken);
return accessToken;
} catch (e) {
throw e;
}
}
//return access token
response = JSON.stringify({
statusCode: 302,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': 'true',
'Cache-Control': 'no-cache',
},
body: {'token': token},
});
console.log(response);
return res.send(response);
}

Related

How to get 'public_Profile' of the user from the Facebook access_token using OAuth2

I wanted to use facebook login in the app. I successfully get Facebook Accesstoken and even the user info {id:'###', name:'###'}. But I wanted the users Email and other public_Profile info to register his email and other details. How can I do that. Following is my code..Did my scope values are wrong? how can I get public_profile info, particularly email to register it in my app.
const getFbToken = async (code) => {
const tokenUrl = "https://graph.facebook.com/v12.0/oauth/access_token";
const queryValues = {
code,
client_id: FB_APP_ID,
client_secret: FB_SECRET,
redirect_uri: redirect_uri, // address must match with google redirect uri
scope:"user_about_me,read_stream,publish_actions,user_birthday,offline_access,email",
};
const token = await axios
.get(tokenUrl, {
headers: {
"Content-Type": "application/json",
},
params:queryValues
})
.then((res) => {
console.log('response', res.data)
return res.data
}
) // returns {{access_token, refresh_token, Authorization Bearer and id_token}}
.catch((error) => {
console.error(`Failed to fetch auth tokens`, error.response.data);
});
console.log(token);
return token;
};
const getFbUser = async (access_token, token_type) => {
const fbUser = await axios
.get(
`https://graph.facebook.com/me`,
{
headers: {
Authorization: `Bearer ${access_token}`,
"Content-Type": "application/json",
},
}
)
.then((res) => res.data)
.catch((error) => {
console.error(`Failed to fetch user`);
throw new Error(error.message);
});
console.log('fbUser',fbUser)
return fbUser;

No response when using ManagementClient in AWS Lambda

We are building a serverless service to perform user management by using node-auth0 sdk but it cannot work as well as the direct api call.
Basic AWS serverless set up:
//aws lambda
exports.handler = async (event) => {
const auth0Management = await createAuth0Management();
let response;
const requestBody = JSON.parse(event.body.toString());
const createUserResponse = await createAuth0User(auth0Management, requestBody);
response = buildResponse(200, createUserResponse);
return response;
};
function buildResponse(statusCode, body){
return {
statusCode: statusCode,
headers:{
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
}
}
Wait auth0 sdk to generate the client:
async function createAuth0Management(){
return new ManagementClient({
domain: process.env.DOMAIN,
clientId: process.env.CLIENTID,
clientSecret: process.env.CLIENTSECRET,
scope: process.env.SCOPE
});
}
We followed the Auth0 Gitghub docs to call Auth0 management API V2 throught the created auth0Management:
async function createAuth0User(auth0Management, userInfo){
const body = {
email: userInfo[0],
username: userInfo[1],
password: userInfo[2],
connection: 'xxx'
};
//sdk cannot create user
await auth0Client.createUser(body)
.then(function (response){
console.log(`create user success: ${response}`); // <- can not see in cloudwatch
})
.catch(function (err) {
console.log(`create user error: ${err}`); // <- can not see in cloudwatch
});
}
However, we can create the user by calling the api directly
async function createAuth0User(auth0Management, userInfo){
const body = {
email: userInfo[0],
username: userInfo[1],
password: userInfo[2],
connection: 'xxx'
};
//api can create user
await doPostRequest(body).then(()=> {
console.log('created'); // <- it works
})
}
const doPostRequest = (body) => {
return new Promise((resolve, reject) => {
const options = {
host: 'xxx',
path: '/api/v2/users',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization':"Bearer xxx"
}
};
//create the request object with the callback with the result
const req = https.request(options, (res) => {
resolve(JSON.stringify(res.statusCode));
});
// handle the possible errors
req.on('error', (e) => {
reject(e.message);
});
//do the request
req.write(JSON.stringify(body));
//finish the request
req.end();
});
};
Could anyone give us some help on this, please? Thanks.

Using request-promise to make an API call using jwt. [ERR_INVALID_ARG_TYPE] received

I'm learning nodejs and trying to make an API call. The API uses JWT to authenticate.
I created these functions to sign a token:
function token() {
const payload = {
iat: Math.floor(new Date() / 1000),
exp: Math.floor(new Date() / 1000) + 30,
sub: "api_key_jwt",
iss: "external",
jti: crypto.randomBytes(6).toString("hex")
};
return new Promise((resolve, reject) => {
jwt.sign(payload, privatekey, { algorithm: "RS256" }, function(
err,
token2
) {
if (err) reject(err);
else resolve(token2);
});
});
}
exports.genToken = async function() {
const header = {
"x-api-key": api
};
const data = {
kid: api,
jwt_token: await token()
};
async function authorization(req, res) {
try {
const auth = await rp({
url: authurl,
method: "POST",
headers: header,
body: data
});
res.send(auth.body);
} catch (error) {
res.send(404).send();
}
}
return {
"x-api-key": api,
Authorization: "Bearer " + authorization()
};
};
This works fine. Then I created a function to make the API call:
const token = require("./index").genToken;
const rp = require("request-promise");
exports.getOrderBook = function(res, error) {
const full_url = url + "order_book";
const auth = token();
rp({
url: full_url,
method: "GET",
headers: auth,
body: {
market: "btceur"
},
json: true
})
.then(function(response) {
res(response);
})
.catch(function(err) {
error(err);
});
};
And I call it using Express:
routes.get("/orderbook", async (req, res, next) => {
try {
const book = await orders.getOrderBook();
res.send(book);
} catch (error) {
next(error);
}
});
However, when I call my API, it shows an error in console:
TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be one of
type string or Buffer. Received type object.
I guess the error is something with the token generation, because if I console.log(auth) in the getOrderBook function, it shows Promise { <pending> }, so probably an object is being passed as the jwt token.
Is it really the problem? I tried a lot of different solutions that I found on internet, however the concept of Async/Await is new to me, and I'm having some troubles to figure it out.
Thanks a lot in advance guys!
Since getToken is an anync function, the return is wrapped in a Promise as well so you would need another anync/await:
exports.getOrderBook = async function() {
let response;
try {
const full_url = url + "order_book";
const auth = await token();
response = await rp({
url: full_url,
method: "GET",
headers: auth,
body: {
market: "btceur"
},
json: true
});
} catch (e) {
// handle error
throw e
// or console.error(e)
}
return response;
};
In this line as well Authorization: "Bearer " + authorization(), authorization is returning a promise
const bearer = await authorization()
return {
"x-api-key": api,
Authorization: "Bearer " + bearer
};
For error handling wrap entire thing in try..catch block
exports.genToken = async function() {
try {
const header = {
"x-api-key": api
};
const data = {
kid: api,
jwt_token: await token()
};
async function authorization(req, res) {
let auth;
try {
auth = await rp({
url: authurl,
method: "POST",
headers: header,
body: data
});
// res object not available
// res.send(auth.body);
} catch (error) {
// res object not available, better throw error and handle in your middleware
// res.send(404).send();
}
return auth
}
const bearer = await authorization()
} catch (e) {
// handle error
}
return {
"x-api-key": api,
Authorization: "Bearer " + bearer
};
}

How to get the response JSON from API call

I want to retrieve the JSON response from the api call I am doing. Example, I want to retrieve something like this:
{"error":{},"success":true,"data":{"user":"tom","password":"123","skill":"beginner","year":2019,"month":"Mar","day":31,"playmorning":0,"playafternoon":1,"playevening":1}}
This is my API call using fetch in react. (yes I know sending password in URL is bad, it's for a school project)
fetch('/api/user/'+ user + '?password=' + password, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
}}).then((res) => {
console.log(res); //I want to get the JSON stuff here
})
This is the API call I am calling.
app.get('/api/user/:user', function (req, res) {
// console.log(JSON.stringify(req));
// var user = req.body.user;
// var password = req.body.password;
var user = req.params.user;
var password = req.query.password;
console.log(user, password);
var result = { error: {} , success:false};
if(user==""){
result["error"]["user"]="user not supplied";
}
if(password==""){
result["error"]["password"]="password not supplied";
}
if(isEmptyObject(result["error"])){
let sql = 'SELECT * FROM user WHERE user=? and password=?;';
db.get(sql, [user, password], function (err, row){
if (err) {
res.status(500);
result["error"]["db"] = err.message;
} else if (row) {
res.status(200);
result.data = row;
result.success = true;
} else {
res.status(401);
result.success = false;
result["error"]["login"] = "login failed";
}
res.json(result);
});
} else {
res.status(400);
res.json(result);
}
});
When I do console.log(res) in the fetch call, this is what is printed:
Response {type: "basic", url: "http://localhost:3000/api/user/tim?password=123", redirected: false, status: 200, ok: true, …}body: (...)bodyUsed: falseheaders: Headers {}ok: trueredirected: falsestatus: 200statusText: "OK"type: "basic"url: "http://localhost:3000/api/user/tim?password=123"proto: Response
When I visit the website, the output is:
{"error":{},"success":true,"data":{"user":"tom","password":"123","skill":"beginner","year":2019,"month":"Mar","day":31,"playmorning":0,"playafternoon":1,"playevening":1}}
This is what I want.
In general, this is how you return the response body from the Promise.
fetch(`${baseUrl}/api/user/${user}?password=${password}`, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
}})
.then(response => response.json())
.then‌​(data=> {
console.log(data);
})
Try this way to parse the response:
fetch('/api/user/'+ user + '?password=' + password, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
}}).then(async (res) => {
const raw = await res.text();
const parsed = raw ? JSON.parse(raw) : { success: res.ok };
console.log(parsed);
})
In this case you can also add some checks for response statuses (if you want, of course) along with parsing the result JSON.
for you to get the JSON body content from the response, you need to use json()
fetch('/api/user/'+ user + '?password=' + password, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
}}).then((res) => {
const jsonData = res.json();
console.log(jsonData);
})
try this
fetch(${baseUrl}/api/user/${user}?password=${password},{
method:'GET',
headers: {
'Accept': 'application/json',
'Content-Type':
'application/json',
}}) .then(async(response ) => {
await response.json()
})

can't set authorization on header request?

i already have this code on my express server:
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Authorization");
next();
});
app.use('/graphql', graphqlExpress(async(req) => {
let {user} = await getUser(req.headers.authorization);
return ({
schema,
pretty: true,
graphiql: true,
context: {
user
}
})
}))
I thought it was cors problem so I followed from this tutorial in enable-cors for express: https://enable-cors.org/server_expressjs.html
This code is how i process fetching:
let token = localStorage.getItem('token');
const fetchQuery = (operation, variables) => {
return fetch('/graphql', {
method: 'POST',
credentials: 'same-origin',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': token,
},
body: JSON.stringify({query: operation.text, variables})
}).then(response => {
// A better error message for request timeouts
if (response.status === 504) {
return Promise.reject({
error: {
message: 'Request timed out'
}
})
}
return response.json()
}).then(responseJson => {
// https://github.com/facebook/relay/issues/1816
// https://github.com/facebook/relay/issues/1913
if (responseJson.errors) {
return Promise.reject(responseJson.errors[0])
}
return Promise.resolve(responseJson)
})
}
But, even though there's already a token after a user logs in, the authorization sent to server is always null?
localStorage.getItem("token") is not executing, probably due to getItem being an I/O operation, and how exporting works. Move it inside fetchQuery
const fetchQuery = (operation, variables) => {
const token = localStorage.getItem("token");
return fetch('/graphql', {
method: 'POST',
credentials: 'same-origin',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': token,
},
body: JSON.stringify({query: operation.text, variables})
}).then(response => {
// A better error message for request timeouts
if (response.status === 504) {
return Promise.reject({
error: {
message: 'Request timed out'
}
})
}
return response.json()
}).then(responseJson => {
// https://github.com/facebook/relay/issues/1816
// https://github.com/facebook/relay/issues/1913
if (responseJson.errors) {
return Promise.reject(responseJson.errors[0])
}
return Promise.resolve(responseJson)
})
}

Categories