Google ClassRoom OAuth Integration Spring Boot - spring-boot

I am creating a web application with Spring Boot and JSF and my intention is to create courses in google classroom from my application.
I followed the example of Google to authenticate myself by Oauth: https://url.miapp.io/oS2mx
Implement that ClassroomQuickstart class from the example, but when you use the method getService() in my web application, it sends me in the Tomcat Embeded Console (Spring Boot) a Google URL for authenticate by myself from a browser and I can continue with the flow of my code.
In other words, authentication works in interactive mode waiting for me to authenticate from the browser so the application can continue the execution flow, I don't know what I should do so that I don't have to authenticate myself in this way, I don't know if it's the code that implements it as it is or has to do with the configuration in the google developer console.

3-legged OAuth:
You are currently following a 3-legged OAuth process, in which there are three parties involved: (#1) end-user, (#2) application and (#3) authorization server. In this OAuth flow, users need to give explicit consent to the application through the browser via a consent screen.
2-legged OAuth:
Since you want to avoid that, you should use a service account to access this application, so that users are not directly involved and user consent is not required. This workflow is usually called 2-legged OAuth (only the application and the authorization server are involved). See Using OAuth 2.0 for Server to Server Applications for a more in-depth explanation.
Since you don't want the service account to run the application by itself, but to act on behalf of other accounts in the domain, you should grant it domain-wide authority so that it can impersonate other accounts in the domain.
Workflow:
To achieve this, you have to follow these steps:
Create a service account by following this guide.
Delegate domain-wide authority to the service account (you have to be a domain administrator to do this): this step authorizes the service account to access data on behalf of any user in the domain. Follow the steps indicated here.
Once you have delegated domain-wide authority, you have to modify the code related to the building of the OAuth credentials. Use, for example, the code sample provided in this answer:
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId("service-account#email-address") // Service account email
.setServiceAccountPrivateKeyFromP12File(new File("your-credentials.p12"))
.setServiceAccountScopes(Collections.singleton(ClassroomScopes.CLASSROOM_COURSES))
.setServiceAccountUser("user#email-address") // Your email address (address of the user you want to impersonate)
.build();
In this case, user#email-address refers to the account on behalf of which the course should be created. In order words, it will be the account that the service account should impersonate. Regarding theP12 file, it should be downloaded from the Cloud Console, as explained here. This can be done with a JSON file instead of P12 (see here).
Reference:
Using OAuth 2.0 for Server to Server Applications

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

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.

How can I change the client_email for the service account key credential to my own email?

I have 2 applications, the old application is using Oauth2 to access the Google Analytics API. All current users have granted access to an email from my domain.
The second application is using credentials with Service account authentication.
The problem is that the email for the Service account keys is using a different domain:
"client_email": "xxx-service#xxx.iam.gserviceaccount.com",
I need it to use my old email from my domain that already have permissions from clients.
How can I do that, I already downloaded the json file for the Service account keys.
There is a diffrence between Oauth2 and service accounts.
Lets start with the old app using Oauth2. When a user starts using the application they are displayed the authentication form which asks them to grant application X access to their data. Assuming they accept it application X can now read there data. Application X is given a Refresh token which can be used to access the data at a later date.
In the background the developer of Application X registered their application on Google Developer console and was given a client id and client secret. When the user authenticated to the application the Refresh token is created using the client id and client secret. You can not take a different client id and client secret and use it with the refresh token from another application they are not interchangeable.
Service accounts are different in that they are preauthorized. If you take that service account email address you have and add it as a user on the Google analytics website admin section. The service account will have access to read the information just like any other user.
Clarifications / answers.
You can not pick the service account email address these are generated by Google.
You can't use a service account to access data granted to an application though Oauth2. they are not interchangeable.
If you have access to the users data using Oauth2 you should be using your refresh tokens to access their data you do not need a service account.

send emails from MY gmail account with OAuth2 and nodemailer

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.

Resources