Server-side OAuth for user impersonation via GMail API - gmail-api

I am trying to perform server-side OAuth so I can use a specific user account in my domain to send emails (hence using GMail API) via my application.
Mine is a purely server-side app and I cannot perform "user consent" via a UI.
I have created a project in Google App Engine and have obtained service account credentials (P12 key).
My code looks like this -
new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(googleEmailerServiceAccountId)
.setServiceAccountPrivateKeyFromP12File(new File(googleEmailerServiceAccountPrivateKeyLocation)).setServiceAccountScopes(Collections.singleton(GmailScopes.GMAIL_COMPOSE))
.setServiceAccountUser("xxx#xxx.com")
.build()
I have delegated domain wide access to the application (for GMAIL COMPOSE scope) via the admin console as per https://developers.google.com/identity/protocols/OAuth2ServiceAccount.
And I still get an Unauthorised 401 when I try to send emails from my app.
Since there is no explicit documentation for the Gmail API that says it allows domain wide delegation, I am guessing it is not allowed for Gmail.
Is there any way of achieving this programatically?
Any idea would be much appreciated.
Thanks!

As far as I know you cant use a service account with Gmail. Service accounts must be pre authorized.
Authorizing Your App with Gmail
All requests to the Gmail API must be authorized by an authenticated
user. Gmail uses the OAuth 2.0 protocol for authenticating a Google
account and authorizing access to user data. You can also use Google+
Sign-in to provide a "sign-in with Google" authentication method for
your app.
Share a Google drive folder with the Service account. Add the service account email as a user on a google drive folder it has access
Share a Google calendar with the service account, just like any other user.
Service accounts don't work on all Google APIs. To my knowledge you cant give another user access to your Gmail so there will be now to pre authorize the service account.
Recommendation / work around / hack
Create a dummy app using the same client id, authenticate it get the refresh token then use the refresh token in your application.

Related

How to perform authentication with Google Cloud Endpoints?

We are migrating part of our web app to a native mobile app (iOS and Android). We store all user info in our own database, including authentication info (username & pwd). We have a REST API for use by mobile apps and are trying to implement that in Google Cloud Endpoints.
We use an API key for identifying the app.
We want to also authenticate each user. The app will request the username and pwd and then pass that through the REST API. Our backend will confirm (by looking up the username/pwd in the db) if the user is valid. Ideally, at this point we would return a JWT.
Can this be done? The GCE documentation talks about authenticating Google users, and Facebook users. We don't want that. We don't want to use Firebase (unless a custom mechanism can be set up to authenticate). We will manage accounts. We will check if the username and pwd provided (through the app) identifies a valid user.
In trying to use a backend based on Google App Engine Standard and ESPv2, the documentation states that IAP must be enabled. IAP appears to authenticate users in a way we don't want. We want to authenticate users based on the username and pwd they provide and that we manage. Can this be done?
Any pointers would be greatly appreciated.
Thank you.

Access Google IAP protected API from Angular

My application has 2 modules
Spring boot back-end API
Angular front-end (SPA application)
Both were deployed in Google app engine (GAE).
I used Google IAP for authentication. After enabling the IAP is there any way to generate the IAP JWT token for the different users within the organization to authenticate the APIs from the web client.
I tried token generating mechanism using the Service account. But for my scenario, I just want to authenticate and authorize users not service account. I found this reference to enable the web resource access for users, but it is using cookie based authorization. And it is not the recommended way for the application such as angular.
If you're using IAP to protect your backend api, it means your users have a Google Account or an account managed in Cloud Identity.
In your Angular front-end app, you can retrieve JWT token of your user, with Google Sign-In for Websites.
To easily integrate Google Sign-in with Angular, I recommend you to use ng-gapi from Ruben.
Main lines of the workflow :
Angular uses ng-gapi with Google Sign-in behind the scene
Users are authenticated with their Google Account
You're able to retrieve GoogleUser idToken which is a JWT token.
Each HttpRequest could be executed with Authorization: Bearer JWT
IAP will accept request.
To better understand how to use ng-gapi, check this stackblitz Demo made by creator of lib.
I also suggest you theses resources :
My answer on Stackoverflow about Angular stateless authentication workflow. Just skip the Spring Boot JWT part if you're using IAP.
Google Sign-In for Websites official docs.
Note that you need to use the OAuth 2.0 Client ID configured by Identity-Aware Proxy for your app, and add the correct Authorized JavaScript origins.
Yes, You can generate a JWT token using angular-oauth2-oidc.
Get the default IAP Web App client ID and client secret. Use AuthConfig and redirect to your link after credentials are entered; you can capture the token after they are redirected.
This link has all the details:
https://medium.com/#ishmeetsingh/google-auth-integration-with-angular-5-and-angular-oauth2-oidc-ed01b997e1df
You have told that you tried authenticating from service account. Were you able to generate JWT for service account? I am able to capture the JWT token for individual accounts and use it.
Please give more information on how you authenticated from service account.
Thanks,
Bharath

Login with my organization Google account with Google Cloud Endpoints

Is it possible to limit my endpoints api to my organization's Google accounts?
P.D.
I do not have access to the Administrator account.
Thanks
You could protect your API method by injecting the User object. Now, when the API Method is invoked, you can check for the User object and get the Email Addresses and Authenticating Domain to perform your check and move ahead in your API Method.

Can App Engine MailService be used with OAuth2 / service accounts?

We are using UserService with OpenId to send emails on behalf of the logged in user.
As we want to move to OAuth2/OpenID Connect for login to comply with the new marketplace guideline I'd like to know if it is possible to use App Engine's MailService with OAuth2 / service accounts to be able to send emails on behalf of the user.
I know that it is possible to send emails using the old GMail API, but then we are stuck with the daily GMail limits which are far too low for our usecase.
You can use the current GMail api via OAuth 2 and you can impersonate users with Service Accounts. There isn't a specific example for Gmail + Service accounts but Drive has good documentation that you should be able to extrapolate. If the quota limits are unmanageable, than you'll need to evaluate IMAP if you want a Google-powered solution.

Can we specify a domain when redirect user to sign in with oauth2 in appengine?

When we were using the UserService api, we can specify a domain when generate auth url. But when we switch to oauth2 (with google client library for java API), we are using AuthorizationCodeFlow.newAuthorizationUrl() to generate auth url, however we cannot specify any domain, so for example, if one customer already logged in with his gmail account in some other google sites, but he want to sign in our app with another google apps account, he has to logout from google site since the authFlow always get the gmail account credential, we don't have a way to force him log in to a specific domain. We didn't have this issue when using UserService api.
Just want to know if there is any solution for this.
If you attach "hd=$domain" to the OAuth2 authorization request query parameters it will prompt user to login to that domain (if user not yet logged in) and/or optimize selection of the user's account in that domain.

Resources