send emails from MY gmail account with OAuth2 and nodemailer - google-api

I want to send emails from my gmail address through my own server. I'm using nodemailer and using account credentials is flaky, and often times doesn't work and leads to this thread
I've implemented everything on that thread many times, and still it's flaky, and also I know OAuth2 is the way to go.
I have a project with cliendID and clientSecret in google developer console, as you can see:
But how do I get an access token WITHOUT any browser interaction?
I seem to be missing something trivial here ...
I've went through all google tutorials and docs I could find about OAuth2, tokens, and APIs, but all guides go through the browser in one point.

Go to the OAuth Playground, click the cog on the top right, check the Use your own OAuth credentials and insert your clientID and clientSecret.
Then select the Gmail API v1 scopes you want in the list to the left and follow the outlined steps and you will get an access_token and a refresh_token.

Google Oauth2 actually all Oauth2 implementations I am aware of require that a user grant an application access via a web browser.
There is an alternative type called service accounts this is more like oauth1 service accounts are preauthorized. You can grant a service account access to your google drive by sharing folders and files with the service account like you would any other user. Because they are preauthorized there is no browser window pop up with service accounts.
You can only user service accounts with Gmail if you have a Google domains account Gsuite. The admin can go in and grant the service account access to the Gmail account in question. Perform G Suite Domain-Wide Delegation of Authority
If this is a normal user Gmail account you cant use a service account. You will have to use Oauth2 popup the request and save the refresh token so that you can gain access at a later date.

Related

How to programmatically request domain-wide delegation for Google Calendar API?

I've spent a few hours now looking through the docs + reading other SO posts, and it's still not clear to me how to simply request domain-wide credentials for Google Calendar API (for other domains; not my own).
Our current web app kicks off an OAuth flow to request Calendar API credentials for a single user; however, there doesn't seem to be a simple way like this to request credentials for an entire domain. It seems that acquiring domain-level access requires the admin to manually set up a service account and then pass that information over (https://developers.google.com/admin-sdk/directory/v1/guides/delegation) which is incredibly cumbersome.
With Microsoft's Calendar API, this is a very straightforward process where you simply specify "Application Permissions" and then the OAuth flow must be completed by an Admin to get the expected set of access and refresh tokens. For GSuite, I can find no such equivalent...
To clarify based on some comments, I'm trying to figure out if GSuite has anything equivalent to what Microsoft Graph offers as described here:
https://learn.microsoft.com/en-us/graph/auth-v2-service
The closest I've seen requires publishing to the Google Apps Marketplace; however, the documentation here seems to be quite lacking and it's unclear how things like redirect_uri for handing over credentials to the backend server are handled.
If I've missed any documentation and someone can just point me in the right direction then that would be greatly appreciated.
The best documentation for how to set up domain wide delegation to a service account is -> Perform Google Workspace Domain-Wide Delegation of Authority
request domain-wide credentials for Google Calendar API (for other domains; not my own).
You can not. The admin of the google workspace domain sets up domain wide delegation for service accounts owned by the domain.
there doesn't seem to be a simple way like this to request credentials for an entire domain.
Service account authorization is very different from Oauth2 authorization. Service account authorization is is intended for backend systems that need access to data without requesting user permission.
Oauth2 allows you to grant authorization on a per user basis. The user must grant an application access to their data by accepting the consent screen.
There is no oauth2 flow that would grant your application to all the users on a workspace domain. TBH I think thats a good thing.
Only super administrators can configure domain-wide delegation, this is done in the Google Workspace Admin console
When you enable domain-wide delegation for a service account, basically you are giving it the permission to impersonate any user within your domain
If you need to make Calendar requests on behalf your users, in your app you will need to implement impersonation, that way you will use the service account with wide-domain delegation to make the requests on behalf your users
Here you can find the documentation explaining how to set up wide-domain delegation and an example for making the API calls implementing impersonation https://developers.google.com/identity/protocols/oauth2/service-account#authorizingrequests

Sending automated emails using Gmail API with Java and Oauth authentication

I have a web app which sends emails (gmail) in name of my users
When a user registers, she supplies gmail account and password. Also she has to enable access for Less Secure Apps (I recommend to create a new account for this)
Then I can open a gmail session
session = Session.getInstance(props, new javax.mail.Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(user.getEmail(), user.getPassword());
}
});
and send emails on her behalf.
Unfortunately this is going to stop working next 30th May, when Google will allow only OAUTH2 access
I have followed Java Quickstart for Gmail API and I have code up and running for sending emails with OAUTH2: enable gmail api, create an application on google cloud platform, grant send permission, oauth2 client id credential created...
The problem I have is I can't see a way to automatize this task because when creating an authorized credential, a consent screen displays on browser and you have to select the account to be granted manually (maybe because my app in google cloud platform is still pending to be reviewed)
Is there a way to infer the gmail account you want to access from the credentials file (client_secret.json)? Is there a way to automatize this?
No, or yes. It depends.
The whole point of OAuth2 is to improve security by working with authorization tokens rather than asking for user credentials. To do this the user has to consent to the app's access request, and thus the OAuth consent screen cannot be bypassed. This is
explained in Google's documentation. It's not related to your app's review status but rather it's the way OAuth works.
You can still work in a similar way, though . Instead of asking for username and password upon the user's registration you can redirect them to the OAuth consent screen so they can authorize your app. Make sure that your app is requesting offline access type and then you can retrieve an access_token and a refresh_token. These will essentially work as your credentials and you can use the refresh token to generate new access tokens when needed without having the user go through the consent screen each time.
The refresh token doesn't have a "natural" expiration so you can keep using it indefinitely, but there are a few scenarios where it will become invalid, such as it not being used for six months, the user changing passwords (if using Gmail scopes), the user manually revoking access, etc. In these cases you will need to direct them to the consent screen again to reauthorize your app.
In this sense, your app can still work automatically without user input except the initial setup, which you already had to deal with when they supplied you with their credentials. The refresh token expiration can even be compared to what you had to do when the users changed their passwords in your current workflow.
One exception to this are service accounts. If you and your users are part of a Google Workspace domain you can delegate domain-wide access to it, then the service account will be able to access user data without any manual input. Of course, this is because as the domain administrator you pretty much own all the accounts under it. But if you're working with a publicly available application you will have to deal with the limitations I mentioned above.
Sources:
Google's auth overview
Using OAuth 2.0 to access Google APIs
OAuth 2.0 for web applications
The OAuth consent screen

How to send service emails via Gmail (machine-2-machine) with secure restrictions?

How to send service emails
from my backend with smtp.google.com or Gmail API while making sure
the secret stored on the backend server can only be used to send emails from a specific sender?
Goal
send user account activation emails from my backend
use smtp.google.com or Gmail API (i.e. no own SMTP server)
authenticate with OAuth2.0 (i.e. don't enable "less secure apps")
Current state
implemented the email sending part
for testing, I created a noreply#**.** Google Suite account
for testing, I generated an accessToken via OAuth2 Playground
using the accessToken I can send emails via smtp.googl.com
Problem
Google suggests to use a service account for this
But to send emails from no-reply#x.y I have to enable Domain-wide Delegation
Domain-wide delegation allows to impersonate every domain account
the secret stored on the backend should only allow to send mails from no-reply#**.**
Lets start with send user account activation emails from my server I am gong to assume that you have a web app. This web app allows users to register with your system. Now when a user registers with your system you want to automatically send them an account creation email. Your idea is to use Google rather than setting up your own smtp server and sending these emails from your own system. Not a bad idea really.
Lets think about this for a minute the emails would need to be sent automatically so you need some kind of service sending them. To do that you want to use a service account. Again this is a great idea using a pre authorized service account that you will not need to have a user to authorize the app.
The only issue is that service accounts do not work with normal gmail accounts. To use a service account with Gmail api you need to use a google workspace domain account. The workspace domain admin would then be able to add permissions to the service account letting it act like a user on the domain. In this case your idea of no-reply.
So your workspace domain account would have a user called no-reply. The domain admin would then configure domain wide delegation to the service account allowing it to pretend that it is the user called no-reply. For all intents and purposes the service account is the no-reply user. It will be able to send mails as if they are coming from that user.
For all this to work you will need the workspace account with that user.
Have a look at the following link, it's actually one of Google's better examples it shows how to set up the delegation.
Perform Google Workspace Domain-Wide Delegation of Authority
Here you create a service account with credentials, allow this account to impersonate other users (e.g. the no-reply user), to only use the Gmail API and to only use it to send emails.
the documentation is a bit outdated, you can skip the step Grant users access to this service account and create the service account key afterwards via the service account edit function: Manage keys
in the step Domain wide delegation you need Google Admin not the Google Cloud Platform Admin Console as in the previous step
Just remember to swap out the lines about
https://www.googleapis.com/auth/admin.directory.user,
https://www.googleapis.com/auth/admin.directory.group
and use
https://www.googleapis.com/auth/gmail.send
instead as you want to access the Gmail API and only allow the service account to send (not read) emails
tip
in the sample code in that link
.setServiceAccountUser(userEmail)
userEmail is the email address of the user you want to impersonate in this case no-reply#x.y
So I guess what I am saying is that what you want to do is definitely possible, however, it may be easier just to set up your own SMTP server.

Gmail with OAuth: How to access the users mailbox on behalf of the user?

As Google does not support "client_credentials" grant in OAuth, how can I access the users mailbox on behalf of him (machine to machine)?
My Java application would be able to store any user credentials in a secure place.
Thanks for a pointer :)
UPDATE
Thank you for your response. But I am not sure, if this explanation solves my use case. Let me better describe the environment:
Since several years, I have a background Java task which runs without user interventions:
The user enters once his normal username and password credentials which are saved in a secure place.
The Java task regularly connect (thru IMAP) to the users mail box (e.g. john.doe#gmail.com) thru the Java Jakarta Mail API to read and process any new incoming mail from the users inbox.
To support a more modern authentication, I would like to switch the authentication to OAuth 2.0. The used Jakarta Mail API already support the IMAP connect thru the use of an access token, so I only need to add the code to ask the authorisation server for the access token.
Questions:
Is this possible with Google OAuth?
Which OAuth grant type must be used? First I thought "client_credentials" should be used, but Google do not currently seem to support it.
Thanks!
Domain-wide delegation lets you do that:
In Google Workspace domains, the domain administrator can grant third-party applications with domain-wide access to its users' data — this is known as domain-wide delegation of authority. To delegate authority this way, domain administrators can use service accounts with OAuth 2.0.
This is obviously a very powerful capability, so make sure to:
protect the service account appropriately
only grant the least set of OAuth scopes that's necessary.
Note that domain-wide delegation doesn't necessarily require service account keys.

When Service Account should be used to access google api?

I am trying to use google api for getting new emails from gmail account. However reading the docs I found that there are two types to access api the first one without authorization (with json credential) and second one one is Service Account (with p12 certificate and secretkey)
Can not understand what the difference between this access? What exactly should I use?
Thanks
Oauth2 is the first type you are looking at. With Oauth2 a consent screen is displayed to the user who must approve your access. Usage you want to access a users Gmail account, you want to access a users google calendar, you want to access a users google drive.
With a service account access is pre-authorized by taking the service account email address and adding it as a user for data in question. Usage: You want to allow other users to upload files to your google drive account, you would add the service account email address to a folder on google drive then the service account will be able to upload to that folder with out having to prompt any user for permissions.
Use Oauth2 when you want to access a users account, use a service account when you want to access an account controlled by you the developer.
If you want to access a users Gmail account you need to use Oauth2 you cant grant another user access to your Gmail so there is no way to give a service account access to it.

Resources