I'm getting a redirect_uri_mismatch when deploying my Node.js app to Heroku using Google OAuth2 - node.js

I'm tasked with making a server using Node.js which will read emails from a Google account and parse the content from those emails into data we can store in a database. I'm using Google's googleapis package (v103.0.0) in NPM to authenticate/authorize with whichever account we'd like to use.
The issue comes when we try to switch accounts and have the user re-auth. During development on a local machine, the Auth process works as expected:
The client requests an Auth URL.
The server generates a new Auth URL and sends it back to the client.
The client redirects to that URL and the Google Consent Screen is shown.
The client is asked to choose between logged-in Google accounts.
The client authorizes the application and is redirected back to the server with a code.
The server uses the code to generate/save a token, which allows it to use the Gmail API.
However, after deploying to Heroku, the Google Consent Screen no longer allows the user to select an account. Instead, at step 3, it shows this message. In just about every other question related to this error, there's always additional information below the error code/message, but nothing's there for me. I made sure: (1) the domain I'm using in Heroku is verified on the Google Cloud Console, and (2) the redirect_uri within the Node.js application is passing the correct domain to the Auth URL, even while in production.
I can't provide the URL for privacy reasons, but let me know if there's any source code or Cloud Console info I should include.

It didn't take long after posting this question, but I realized I was using an incorrect OAuth 2.0 Client ID type. I was attempting to use "Desktop" when I should've been using "Web application" instead. Take a look at this image to see the difference.
When you select "Web application", you're given some new options: Authorized JavaScript origins, and Authorized redirect URIs. This is where you need to fill out the allowed URIs. Here's a sample of what that should look like.

Related

How to setup OAuth2 connection to Google Identity API within an Electron app safely with redirectUri pointing to localhost?

The context:
I'm trying to develop a desktop app with ElectronJS which needs access to Google APIs. As such, I want my users to be able to connect to their Google account via OAuth2.
As I use Electron, I have no safe way to store a "client-secret" and must use the "mobile app" method.
The problem:
Google keeps rejecting my redirect_uri:
The doc I followed:
The official npm "google-auth-library" package mentions the following regarding OAuth authentication for Electron apps ("OAuth2 with Installed Apps (Electron)" section) :
If you're authenticating with OAuth2 from an installed application (like Electron), you may not want to embed your client_secret inside of the application sources. To work around this restriction, you can choose the iOS application type when creating your OAuth2 credentials in the Google Developers console
As doing so gave me the previously mentionned Error 400, I looked into Google Identity documentation and saw this regarding localhost redirection:
Note that support for the loopback IP address redirect option on mobile apps is DEPRECATED.
My question:
At this point, I suspect that this is the reason Google is responding Error 400 to my requests (but I admit it could be my fault. I just don't understand what I do wrong as I feel like I follow the documentation strictly.)
If so, what are the possible ways to solve the issue ? Knowing that I have strictly 0 budget for this project and so I cannot afford to redirect to a domain I would buy or afford a server acting as proxy between my app and Google APIs.
(The code, if useful)
I use the "complete OAuth2 example" from google-auth-library except I changed the OAuth2Client constructor call to this, following the doc's recommandations:
const oAuth2Client = new OAuth2Client({
clientId: "<the clientID of my project from Google API Console>",
redirectUri: "http://127.0.0.1:3000"
})
In despair, I've tried a whole lot of different URL formats, but nothing works.
Thanks in advance for your help.
OAUTH BEHAVIOUR
An OpenID Connect desktop app uses PKCE without a client secret. According to RFC8252 it then receives the login response on either a loopback URL or via a private URI scheme notification.
The loopback option is fine for a desktop app but should not be used for a mobile app. Conversely, claimed HTTPS redirect URLs work for mobile apps but not desktop apps.
TROUBLESHOOTING YOUR PROBLEM
It is not clear whether your problem is caused by using a loopback URL or something else. To troubleshoot, you can use a couple of demo Electron apps of mine:
Loopback example
Private URI Scheme example
In both cases, edit the desktop.config.json file in the root folder. Replace my AWS Cognito values with your Google values. Then run npm start. See if that gets you any further, and post any follow up questions.

Starting using Google Sheets API cannot get configuration/token files

I need to get access at the sheets and I am following this guide to start to do that https://developers.google.com/sheets/api/quickstart/nodejs
But the button that enables google APIs doesn't work, all names I put on the project return an error.
I went on the API console and created a new project but I do not know how to get credentials files (if they are needed) and then I must create an URL for the OAuth page?
How to get OAuth crendetials manually
There different types of crendetials and the procedure to obtain them is slightly different depending on your situation.See here for the different scenarios.
In most cases (an exception is when using a service account), the first step is to set up an OAuth consent screen.
The consent screen is the screen your users see when they are prompted to agree to terms that are presented to them by your application
To set up a OAuth consent screen, go after chosing a project from the GCP console on APIs & services -> OAuth consent screen
You need to chose either your application is supposed to accessible only by domain internal users or also external (in the latter case you might need to submit your application for verification by Google, pontentially involving costs - depending on the scopes you use).
You need to provide an application name that your users will see (the logo is optional)
You need to specify which scopes your app will use
You can specify other properties, e.g. the Authorized domains (this is usually your website from which the users will be redirected to the consent screen when performaing some kind of action)
If you are not sure about the optional properties, leave them out for the start
Once you set up the authentication screen, the second step is to go on APIs & services -> Credentials
Read the Authentication overview to decide which credentials you need
For most applications you will want an OAuth client ID
The diffrent Application types are described here, to start with create a Web Application
Authorized JavaScript origins and Authorized redirect URIs is basically your Webpage from which the users will be redirected to authenticate and to which they should be redirected after authentication.
For local testing you do not need to specify those URLs
Once you create the OAuth2 client successfully, you will obtain the Client ID and Client Secret - your crendetials to incorporate into your code when using Google APIs.
If you click on the download button on the right side of your newly created credentials - it will generate a json file on your local machine from which the credentials will be read automatically if you follow the quickstart.
Alternatively you can paste the credentials directly into your code - see here for sample for different situations

Gmail API Nodejs and PM2 authentication

I have set up code to send emails using Gmail API in Nodejs. It works perfectly well in local machine. It asks to enter a code by visiting URL. Something like,
Authorize this app by visiting this URL: someURL
Enter the code from that page here: copy-paste code here
This is automatically done by Google following Node.js Quickstart for Gmail and it automatically generates token.json. Everything works perfectly fine in development.
Now in production, I deploy my app using PM2 and Nginx. So, now each node server is running in background and logs are generated in files.
I see the above prompt in the log file Enter the code from that page here:. But as the log is piped to the file, I have no way of pasting the code since I don't have access to standard input.
I have tried generating token.json from local and using it in the server which doesn't seem to work.
How do I fix this and is there any way around this?
NOTE: The code to authorize and send mails works just fine. I'm not posting it here because I don't want the question to be cluttered.
If you are trying to make a server application without need of user interaction instead of using regular OAuth you could try to use Service Account.
Although take into account that service accounts don't have the Gmail API per se, so you should enable the Domain-Wide Delegation to impersonate another user of the domain.
If you insist in authenticating a real user, you can retrieve the token.json before implementing PM2 and using it afterwards.
Also you can take a look at these two (1 and 2) github posts that also opens your initial thought of trying to use the stdin to authenticate the user.

When registering an app on Azure Active Direct, what "redirect URI" or "Sign-on URL" should I use?

Might seem a silly question, but Microsoft's documentation isn't very beginner friendly, I think. It uses as examples "http://localhost:31544" for the sign-on url and "http://MyFirstAADApp" for the redirect URI, but although I understand what a local host is I can't figure out what exactly the numbers on it are and how I define them for my application, and absolutely zero clue of what the redirect URI is supposed to do for a native application and how should I define a URI for my own.
To be more clear on what kind of app I'm trying to add, I merely want to acess the Office 365 management API tools and get some data from it, so I imagine a native app would fulfill my needs for now. Registering the app on Azure AD is required to do so according to Microsoft's documentation.
So expanding on the title, how to define an URI for my native app is what I would mainly like to know. Some further clarification on what exactly is the purpose of this URI as well as to how to use and/or define a localhost URL for an Web app would also be much appreciated.
I know this is ancient, but I don't see a satisfying answer here, and maybe someone will come across this and find it useful. To answer the question asked, unless you're going to work outside of the default MSAL handling of the server responses, and I don't expect you would from your description, I'd just go ahead and use the default:
https://login.microsoftonline.com/common/oauth2/nativeclient
When you go into the Azure AD portal, go to your application and, from the Overview, select the "Set RedirectURL" option, you'll add a platform and select the "Mobile and Desktop Applications" and you'll be provided with the choice of 3 URLs to choose from. My understanding is this is just there for custom handling of authorization tokens and is telling MS where to send those tokens. The MSAL library functions seem to use this link as well, so they're probably handling this in the backend.
I agree with the OP though, the MS docs are severely lacking for newcomers and I wasn't able to find an end-to-end description of what needs to happen to get, in my case, a desktop application to send email through Office365 using 2FA. I would forge ahead as best I could until I hit the next error, then explore that, sort it, then slam into the next one. Rinse and repeat. This was made extra tedious as I had to go through a 3rd party IT group to get the 2FA access codes every time I wanted to test.
Best of luck, hope this helps someone!
how to define an URI for my native app is what I would mainly like to
know.
You should provide a Redirect URI that is unique to your application as it will return to this URI when authentication is complete.
In your application, you will need to add a class level variables that are required for the authentication flow, include ClientId and Redirect URI.
Here is the diagram:
Native application makes a request to the authorization endpoint in Azure AD, this request includes the Application IP ,Redirect URI and application ID URI for the web api.
After user signed in, Azure AD issues an authorization code response back to the client application's redirect URI. After that, the client application stops browser interaction and extracts the authorization code from the response.
Then the client app use this code to sends a request to Azure AD's token endpoint. upon successful validation, Azure AD returns two tokens.
Over HTTPS, the client app uses the returned JWT access token to add the JWT string with a “Bearer” designation in the Authorization header of the request to the web API. The web API then validates the JWT token, and if validation is successful, returns the desired resource.
More information about it, please refer to this article.
For native you can set redirect to be equal to the Application ID URI, which now defaults to look like //app:{ApplicationId}
Redirect uri be starts with SSL URL, so select your project, enable SSL URL and use this auto generated SSL URL (for example : https://localhost:port#) as redirect uri , same to be updated in the azure app registration as additional redirect URIs

Standalone app authorization without browser?

Is browser redirection necessary to get autorization and access token ? Is there a way how to get autorization programatically ? I am a bit suprised i found this in the OAuth2 google documentation :
https://developers.google.com/accounts/docs/OAuth2#scenarios > Chapter Installed Application
sequence begins by redirecting a browser (either a browser embedded in the application or the system browser) to a Google URL with a set of query parameters that indicate the type of Google API access the application requires...
We run small java utility app which contains username and password in config file to our google account. i would expect there will be way to get autorization and access token without any browser interaction (it`s a bit hard to do when we run it as a cron job on virtual server)...
It's about trusted path between credentials holder (user), and authentication entity (it can by google app's server, or openID or facebook...). Someone who uses OAuth, provides his credentials to server he trusts, and in turn this server not revealing any secret data about him, provides identity assurance for your app.
So you have to provide trusted path to Oauth porvider. This can be done by opening a simple http server within your app, and opening user browser pointing to it, and then authentication would be done using, browser, and after auth is finished your server would recvive OAuth response and your app could authenticate user.
That's the idea, I would not input my "global" credentials to some app, and trust it that it will not, copy and use them later on. You've registered within specific OAuth provider and only he should know, and recive your credentials.

Resources