Welcome to Part 3 in a series of guides on how to integrate Gmail with Angular and Spring Boot.

As a quick recap: the ultimate goal here is to give users of your Angular app access to their Gmail inboxes. Then, they can send and receive emails (almost) as easily as if they were using the Gmail app itself.

It's a tall order. But somebody's got to fill it.

All the ugly work involving Gmail integration gets handled by a downstream microservice that I've imaginatively named "Email Service." That microservice will also handle the ugly work of using OAuth2 for authentication and authorization.

And it's that OAuth2 piece that this article will focus on. At least part of the OAuth2 authentication process.

But you're welcome to skip this guide and go straight to the source on GitHub. Otherwise, read on.

Where Things Stand

At this point in the series, you've accomplished the following:

  • Created an OAuth2 client ID and secret on Google Cloud Console
  • Enabled the Gmail API via Google Cloud Console
  • Set the necessary properties in your Spring Boot application.properties file 
  • Set up a DataStore implementation with its associated factory
  • Set up a refresh listener

If you haven't done any of that,feel free to begin at Part1 of this series and get busy.

Where You're Going

In this guide, you'll accomplish the following:

  • Gain an understanding of the Google authorization code flow
  • Create a GoogleAuthorizationCodeFlow instance relevant to your requirements

Yep. Just two things.

But those two things cover a lot of software development real estate.

Flowing Like a River

Before I get into the coding, it's important that you understand the flow.

Yeah. The flow.

As in: how things go back and forth between the client and server during this part of the OAuth2 authentication process.

First of all: what is the point of the flow?

Answer: it allows your user to grant your application access to Gmail.

And that makes perfect sense. You application shouldn't have access to the user's inbox without that user's permission.

Now, here's how the flow works:

  • The user logs in to your application. This is why you need a security mechanism in place so you can integrate your local security with Google's OAuth2 solution. I recommend JWT if you don't have a security solution in place.
  • Your application will check if the user already has credentials to access Google protected resources (such as Gmail). If so, then those credentials will be used to grant access.
  • If not, then your application will generate an authorization URL and redirect the user's browser to that URL. That URL will take the user through the whole process of granting your application access to Gmail.
  • Once that's done, Google will send the user back to a URL specified by your app (that URL is called the redirect URL). But that redirect will also include an authorization code as a request parameter.
  • Your application will use that authorization code to get an access token and a refresh token.
  • Additionally, your application will store the user's credentials in the database (here, it's MongoDB) so the next time that the user tries to access Gmail, he or she won't have to go through this whole process again. This would be an excellent time to take another look at that second bullet point.

Now if you read from the second bullet point on down, you'll see that I frequently say "Your application will do this..." or "Your application will do that..."

But what I mean by "Your application will do..." is that the GoogleAuthorizationCodeFlow instance will do all of that. You just have to instantiate it correctly.

The operative word there being "correctly."

So let's take a look at how to do that next.

GoogleAuthorizationCodeFlow

If you've done any kind of OAuth2 work with the Google API, you've probably used a class called GoogleAuthorizationCodeFlow.

It's a beast.

As in: it's what you use to configure pretty much everything.

Now check out how the utility belt uses that class:

	private GoogleAuthorizationCodeFlow getAuthorizationCodeFlow(String userId) throws IOException, GeneralSecurityException {
		List<CredentialRefreshListener> listeners = getListeners(userId);
		
		GoogleAuthorizationCodeFlow authorizationCodeFlow = new GoogleAuthorizationCodeFlow.Builder(
				GoogleNetHttpTransport.newTrustedTransport(), 
				new GsonFactory(), 
				clientId, 
				clientSecret, 
				Collections.singletonList(GmailScopes.MAIL_GOOGLE_COM))
				.setCredentialDataStore(dataStore)
				.setAccessType("offline")
				.setRefreshListeners(listeners)
				.build();		
		
		return authorizationCodeFlow;
	}

Now you can see why I call GoogleAuthorizationCodeFlow a beast. It takes a lot just to instantiate it.

In fact, it's instantiated with a builder class that itself requires quite a few parameters in its constructor. I'll cover them one by one.

The first parameter (GoogleNetHttpTransport.newTrustedTransport()) answers the question: "Which HTTP transport implementation are we using to handle this authentication process?"

The code above uses GoogleHttpTransport because the documentation supports that implementation by saying it's "so easy."

Hey, if it's good enough for Google, it's good enough for me.

The second parameter specifies the library used to parse and create JSON objects. Google recommends GsonFactory here so once again it's good enough me.

The next two parameters are fairly self-explanatory. They're the OAuth client ID and client secret, respectively.

That last parameter specifies the scopes for the request. Those scopes answer the following question: "What is the user allowed to do with this token?"

Since the requirements here involve using the Gmail API, the code sets the scope to GmailScopes.MAIL_GOOGLE_COM. But it needs to put that scope in a List because that's what the constructor requires.

Although those parameters are all that's necessary to construct the builder, the work is still not finished. The code goes on to use method chaining to configure the GoogleAuthorizationCodeFlow object.

The first method, setCredentialDataStore() specifies the DataStore object that you saw in Part 2.

The next method, setAccessType() is set to "offline" because that will enable the auto-refresh of tokens when the user isn't at the browser.

Also: when you set the access type to "offline," you're telling the Google authorization server to return both an access token and a refresh token the first time the user presents an authorization code for tokens.

The next method, setRefreshListeners(), specifies the refresh listeners that I described in the previous section. In this case, there's only one listener but once again it has to be included in a List.

And, finally, the build() method creates the AuthorizationCodeFlow instance.

Wrapping It Up

You're getting there. Just keep hangin' on.

In the next guide, I'll explain how to create a Controller class and a method that will kick off the authorization code flow. You'll need to have Postman on the ready for that.

In the meantime, have fun!

Photo by Nataliya Vaitkevich from Pexels