GSuite API service account - verifying impersonated user credentials through API - google-api

We are integrating Google Calendar with our room booking system. Users in GSuite domain should login on our reservation screen and book a room. So far I made use of an service account with domain wide delegation to impersonate the users (the setSubject() method, passing the e-mail address of the impersonated user). Everything works, although this way we cannot verify if the user we want to impersonate is logged in successfully or not, the event will be just created with him as the organizer, because setSubject() only requires the email to work properly.
In IBM Domino, when using an Java XPage I was able to compare passwords of the user, not in plain text but there was a function which compared plain text with user's hashed password and returned true if they were equal.
As I see Google doesn't have such a thing if I'm right. How could I check if the user can successfully log in programmatically?

If you want to perform actions in Google Calendar on behalf of a currently logged-in user from a web browser, you might want to use OAuth2 for Web Server Applications instead of using a service account with impersonation.

Related

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.

Google API: one authenticated user for all

I need to read/insert events into a specific calendar, using Google API. All registered users (in my app) can read and insert events into the calendar. I don't have to authenticate each user with OAuth 2.0, because the app will not read the user data - only specific account data.
I'm a professor and all my students can read and insert in my calendar. So, they do not need to login (Google Account) to do it, because it's a single account's data.
Is there a way to set a unique key for the main account?
OAuth2 doesn't makes me sense.
Maybe you need a service account here. It is an account that belongs to your application instead of to an individual end-user. Your application calls Google APIs on behalf of the service account, and user consent is not required. (In non-service-account scenarios, your application calls Google APIs on behalf of end-users, and user consent is sometimes required.)
The Calendar API can use the Delegating domain-wide authority to the service account. For example, an application that uses the Google Calendar API to add events to the calendars of all users in a Google Apps domain would use a service account to access the Google Calendar API on behalf of users.
For more information, check these threads:
Delegating domain-wide authority to the service account
How to list Google Calendar Events without User Authentication
Embed Google Calendar only users logged into my website (not necessarily through Google) can see

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.

Using regular Google account as service account

I have an application using Google Drive that must (a) not require user login and (b) populate a document that authorised users can view.
Because of this it appears that using a regular account as a service account is my only option, as described here https://developers.google.com/drive/web/service-accounts
Use regular Google accounts as application-owned accounts
You may create a regular Google account like any user would, by going
through the Google account sign-up flow or by creating an account on
your Google Apps domain. Make sure it is then never used by an actual
person but only by your application.
To be able to access the account’s Drive programmatically you need to
manually go through the OAuth 2.0 web-server flow once and then store
or hard-code the user’s credentials, such as the refresh token, to be
able to programmatically access its Drive. For more information about
the web server flow for Drive, see Implementing Server-side
Authorization.
While it discourages user access, it doesn't ban it. However I am confused by the line
you need to manually go through the OAuth 2.0 web-server flow once and
then store or hard-code the user’s credentials
There doesn't seem to be a documented way to do this (yes, I have searched) - could someone step me though it?
You don't use a regular account as a service account, these are different things. Each one is a type of application-owned account.
The regular account is just a normal Google account that your application uses. Since regular accounts require the manual authorization step (going to the browser, logging in to Google and authorizing your app), you need to do this manually the first time and then save the token. There's some examples in this page. After you save the token, your app can authorize itself without your intervention.
The service account is an account that is not associated with an user and that do not require manual authorization. You can create a service account in the Developers Console as described here. With this type of account, you use a private key file to authorize your app.
Unless you need access to the web interface of the account that will manage your files (for example, to buy more storage), I'd recommend using the service account, since it doesn't require the manual step.

Resources