google-api-nodejs-client throws invalid_request error when exchanging code with tokens - node.js

I've got a simple client app using react-google-login with this settings:
<GoogleLogin
clientId={config.CLIENT_ID}
scope={config.SCOPES.join(' ')}
buttonText="Login With Google"
onSuccess={response => onSignIn('google', response)}
onFailure={this.failure.bind(this)}
accessType="offline"
responseType="code"
/>
It retrieves the code successfully and sends it to the backend server which is written with NodeJS.
The server-side code looks like this:
const { google } = require('googleapis');
const config = global.config;
const oauth2Client = new google.auth.OAuth2({
clientId: config.google.CLIENT_ID,
clientSecret: config.google.CLIENT_SECRET,
});
// code omitted for the sake of simplicity
var authCode = req.body.authCode; // the provided code by google
const { tokens } = await oauth2Client.getToken(authCode);
return tokens;
When I run the code, it throws the error:
{ error: 'invalid_request',
error_description: 'Missing parameter: redirect_uri' } },
code: '400' }
and if I add redirectUrl to Developer Console, client app and server-side app, I'll get redirect_uri_mismatch error.
I'm kind of stuck here and couldn't find anything useful on the web.
Any workaround would be appreciated.

Found the solution
Based on one of the replies (surprisingly, not the answer) on this post,
All I needed to do was put postmessage instead of the actual URL in my client react-google-login button and in oauth2Client config on the server.
no need for the redirect_uri on Developer Console at all.
<GoogleLogin
clientId={config.CLIENT_ID}
****redirectUri="postmessage"****
scope={config.SCOPES.join(' ')}
buttonText="Login With Google"
onSuccess={response => onSignIn('google', response)}
onFailure={this.failure.bind(this)}
accessType="offline"
responseType="code"
/>
const oauth2Client = new google.auth.OAuth2({
clientId: config.google.CLIENT_ID,
clientSecret: config.google.CLIENT_SECRET,
****redirectUri: 'postmessage'****
});
Did solve the issue. 5 hours of working, searching and beating my head to the desk. I wonder why there's no clear documentation on Google Developers website. Or maybe there are and I couldn't find them.

Related

React Native Expo Cli Facebook Authentication - unable to exchange Response type code for access token on server API

I am creating React Native app using Expo and used its inbuilt Facebook.useAuthRequest to generate a response when a user logs in. When I create a response type of Token I am able to take this token and send it to my backend API that successfully uses it to get the user details.
However I had hoped to implement a response type of code and use this on the backend API generate the access Token and then request the user details - as I believe this is the most secure option when sending the code to my server.
The issue that I'm facing is that I keep getting an error when trying to formulate the requst to Graph API and I dont understand why:
error: {
message: 'Missing client_id parameter.',
type: 'OAuthException',
code: 101,
fbtrace_id: 'ARHcoh260kBwj7l9yDHjU-n'
}
I just want to confirm that I believe I have inserted all the correct information into the request, so I am unsure of why this error is saying its missing the cliend_id. Here is my request from my API server:
const { data } = await axios({
url: https://graph.facebook.com/v12.0/oauth/access_token? client_id=${appId} &redirect_uri=${redirectUri} &client_secret=${appSecret} &code=${code},
method: 'get',
});
I just want to confirm that the client_id I have taken from app id I created on the facebook developer page, as well as the client_secret, redirect is the https:// used in the initial request and the code is the code initially received in my client side request.
Thanks in advance for any suggestions :)
Just a quick update on this, I was ablel to reformat the request as I believe it had some errors in the spacing and I moved to using the .env files so now my request looks like this:
const redirectUri = {MY_REDIRECT URL};
const appId = process.env.FACEBOOK_CLIENT_ID;
const appSecret = process.env.FACEBOOK_CLIENT_SECRET;
const { data } = await axios({
url: `https://graph.facebook.com/v12.0/oauth/access_token?client_id=${appId}&redirect_uri=${redirectUri}&client_secret=${appSecret}&code=${code}`,
method: 'get',
});
It seems I have moved onto a new error with the following:
error: {
message: 'Invalid code verifier. Code verifier should be a cryptographically random string using the characters A-Z, a-z, 0-9, and the punctuation characters -._~ (hyphen, period, underscore, and tilde), between 43 and 128 characters long.',
type: 'OAuthException',
code: 1,
fbtrace_id: 'AQKIUad5RRCitb6m977fnFW'
}
I'm a bit stumped for what this means as I have checked and all my values appear correct. My only thought is if I need to do something with the code initially received on the client side?
Ok so I finally figures it out - the issue was the I wasn't sending the code_verifier along with my request to exchange the Auth Code for a token. I ended up sending this code_verifier to my API server then adding this to the request so it looked something like this:
FB.api(
'oauth/access_token',
{
client_id: appId,
client_secret: appSecret,
redirect_uri: redirectUri,
code_verifier: code_verifier,
code: code,
},
function (response) {
if (!response || response.error) {
console.log(!response ? 'error occurred' : response.error);
return;
}
var accessToken = response.access_token;
This then finally gave me the accessToken I was looking for that I can then use to exchange for user details server side.
... and the code_verifier is obtained from request.codeVerifier.
const [request, response, promptAsync] = Facebook.useAuthRequest(...

Botkit Slackbot responds with 401 error every time

I'm trying to create a very simple Slack bot using botkit and Google App Engine, but for some reason I keep getting 401 errors any time I message the bot. The weird thing is that the Slack Event Subscription URL (the one ending in /api/messages) validates correctly, and I get a 200 response in GAE logs and validation within Slack.
But whenever I actually message the bot it always gets a 401 error with no message explaining the error at all. I've tried various combinations of the code below, and have now stripped it down to the bare minimum as found here. Aside from dependencies and a code to decrypt credentials (which I've verified is working as expected), this is my full code at the moment:
botInit();
async function botInit () {
const credentialsRaw = await getCredentials();
const credentials = JSON.parse(credentialsRaw);
const adapter = new SlackAdapter(credentials);
const controller = new Botkit({
adapter: adapter
});
controller.on('message', async(bot, message) => {
await bot.reply(message, 'I heard a message!');
});
}
I have also tried this for the messaging function:
controller.ready(() => {
controller.hears(['hello', 'hi'], ['message', 'direct_message'],
async (bot, message) => {
await bot.reply(message, 'Meow. :smile_cat:')
})
})
and this for setting up the controller:
const controller = new Botkit({
webhook_uri: '/api/messages',
adapter: adapter
});
And everything gives back the same exact 401 error, despite all of them working with the Event Subscription URL verification on Slack.
I had same issue but figured out the problem.
I had been using Client Secret as clientSigningSecret
But I should use Signing Secret !

First step on Google API + GMAIL = bad request

I'm very new on Google API, Eventually I want to send emails using it. But for now I'm trying something a little bit simpler (and then build it up).
List all emails in the inbox.
From Gmail > API > Reference, I followed these steps:
On Google API Console:
Created my application.
Under API & Services > Credentials I created a user with Project/Owner role (just to make sure there is no permission problems in this step).
Then I created a key and download the json file.
At API & Services > Library I enabled Gmail.
And using the Reference I put together this snippet:
app.ts
import { google } from 'googleapis';
import credentials from './credentials';
async function main() {
const auth = new google.auth.GoogleAuth({
credentials,
scopes: [
'https://mail.google.com/',
'https://www.googleapis.com/auth/gmail.compose',
'https://www.googleapis.com/auth/gmail.modify',
'https://www.googleapis.com/auth/gmail.readonly',
'https://www.googleapis.com/auth/gmail.metadata'
]
});
const authClient = await auth.getClient();
const gmail = google.gmail({ version: 'v1', auth: authClient });
const data = await gmail.users.messages.list({ userId: 'me' });
console.log(data);
}
main().catch(console.log);
package.json
...
"dependencies": {
googleapis": "^48.0.0"
}
...
Every time I ran this snippet I got:
[01] GaxiosError: Bad Request
[02] at Gaxios._request (~\node_modules\gaxios\build\src\gaxios.js:85:23)
...
[06] response: {
...
[35] status: 400,
[36] statusText: 'Bad Request',
[37] request: {
[38] responseURL: 'https://www.googleapis.com/gmail/v1/users/me/messages'
...
I tried many diferent configurations on Google API Console. Tried to change the scope (list of urls from line 8 to 12) for many others, change the credentials.json to a .js and .ts format, put in a global variable (GOOGLE_APPLICATION_CREDENTIALS) instead of a direct import. But despite of all my attempts, I got aways the same error.
How can I fix that?
Check out example from here which does exactly what you want. They seem use a sampleclient instead of a credentials library.

How to handle server side error during authentication in react-native

So I was making an app and in that app I have say login with facebook
For login, I am using expo-web-browser
Here is my relevant code,
loginWithFacebook = async () => {
const redirectUrl = await Linking.getInitialURL()
const authUrl = config.backendUrl + '/auth/facebook'
Linking.addEventListener('url', this.handleRedirect)
try {
const authResult = await WebBrowser.openAuthSessionAsync(authUrl, redirectUrl)
console.log(authResult)
Linking.removeEventListener('url', this.handleRedirect)
} catch (err) {
console.warn('ERROR:', err)
}
}
While this works, my problem is on error handling, I am using passport Js on the backend (NodeJS). On successful authentication, I am re-directing to my deep link url
return res.redirect(myapplink://)
and currently, on error (say there is an sql connection error), I am throwing a 500 internal error
return res.status(error.status).send(error.message)
Since typically auth related events are done using href and not using ajaxy request, How would you typically handle the error in this situation? I think the answer for the app and web should be identical but if not can you please suggest the way I can handle error in the app and web.

Github api - how to make authenticated requests?

I am using Nodejs to write a simple web app that needs to read content from readme files using the GH api.
Everything works, but I am can't sort how to create requests as an authenticated user.
Sorry bit of a noob here :-) but is it not enough to add my client and secret key or an access_token as a parameter to my url? I have tried both and both seem to time out after 60 requests instead the 5000 the docs say.
I have looked at this site Github Rate Limits but I think I have done what it says.
Do I need to add a token on my server? Like how public and private ssh keys work? - Sorry, just trying to get an understanding of this.
This worked for me recently for getting a list of issues from Github. Nothing else set up on server or similar.
I used a token created with https://github.com/settings/tokens/new
const chalk = require("chalk");
const sa = require("superagent");
const { getProperty } = require("../context");
async function getIssues(org) {
try {
const url = `https://api.github.com/orgs/${org}/issues?state=open`;
const apiToken = await getProperty("github.token");
const res = await sa
.get(url)
.set("Authorization", `token ${apiToken}`)
.send();
res.body.forEach(issue => {
console.log(issue.title);
});
} catch (err) {
console.error(err);
}
}
module.exports = getIssues;

Resources