Inside google cloud function, I need to exchange code for a token using instagram API.
const code = req.body.code;
const config = {
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
};
const prepReq = () => {
return axios.post(
"https://api.instagram.com/oauth/access_token",
qs.stringify({
client_id: "my_insta_app_id",
client_secret: "my_insta_secret",
grant_type: "authorization_code",
redirect_uri: `my_redirect_uri`,
code: code
}),
config
);
};
try {
const response = await prepReq();
if (response.data.access_token) {
return res
.status(200)
.type("application/json")
.send({
success: true,
access_token: response.data.access_token,
user_id: response.data.user_id
});
} else {
throw new Error(
"Something went wrong during authorization. Please try again."
);
}
} catch (e) {
console.log(e);
return res
.status(400)
.type("application/json")
.send({
success: false,
message: e.response.data.error_message
});
}
However, it still returns error:
data: {
error_type: 'OAuthException',
code: 400,
error_message: 'You must provide a valid client_secret and code'
}
I checked my secrets and ids and it's correct. Also, the API returns success response when I'm testing it using Postman.
Also, I don't know why, but sometimes, but really like once in a hundred attempts, my function returns correct response.
// edit - posting the whole google function code. As it has changed the way I pass the data (found that as a solution in axios documentation, but it's also not working), I'm posting it separately:
exports.socialAuthorizationHandler = functionsRegion.https.onRequest(
(req, res) => {
cors(req, res, async () => {
const code = req.body.code;
const config = {
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
};
const prms = new test.URLSearchParams({
client_id: "my_insta_app_id",
client_secret: "my_insta_secret",
grant_type: "authorization_code",
redirect_uri: `my_redirect_uri`,
code: code
});
const prepReq = () => {
return axios.post(
"https://api.instagram.com/oauth/access_token/",
prms.toString(),
config
);
};
try {
const response = await prepReq();
if (response.data.access_token) {
return res
.status(200)
.type("application/json")
.send({
success: true,
access_token: response.data.access_token,
user_id: response.data.user_id
});
} else {
throw new Error(
"Something went wrong during authorization. Please try again."
);
}
} catch (e) {
console.log(e);
return res
.status(400)
.type("application/json")
.send({
success: false,
message: e.response.data.error_message
});
}
});
}
);
As explained in the doc, to terminate HTTP functions you need to call one of the following method on the response
object: redirect()
, send()
, or end()
.
So you don't need to return anything (as you would do for any background Cloud Function), just call one of these Express.js methods.
So instead of doing:
exports.socialAuthorizationHandler = functionsRegion.https.onRequest(
(req, res) => {
cors(req, res, async () => {
//...
try {
const response = await prepReq();
if (response.data.access_token) {
return res
.status(200)
.type("application/json")
.send({
success: true,
access_token: response.data.access_token,
user_id: response.data.user_id
});
} else {
// ...
}
} catch (e) {
console.log(e);
return res
.status(400)
.type("application/json")
.send({
success: false,
message: e.response.data.error_message
});
}
});
});
you should do
exports.socialAuthorizationHandler = functionsRegion.https.onRequest(
(req, res) => {
cors(req, res, async () => {
//...
try {
const response = await prepReq();
if (response.data.access_token) {
res
.status(200)
.type("application/json")
.send({
success: true,
access_token: response.data.access_token,
user_id: response.data.user_id
});
} else {
// ...
}
} catch (e) {
console.log(e);
res
.status(400)
.type("application/json")
.send({
success: false,
message: e.response.data.error_message
});
}
});
});
As per you comment above, it seems that by correctly ending the Cloud Function, you don't encounter the previous problem.