Welcome to Part 4 of a series of guides that will show you how to integrate Gmail with Angular and Spring Boot.

Clearly, this is a marathon. Not a sprint.

And I'm sorry to say this won't be the last chapter in the series. You've still got a long way to go.

But it will be worth it in the end. I know.

If you prefer to skip all the reading and just look at code, you can do that on GitHub.

Otherwise, read on.

Look How Far You've Come

Thus far, you have:

  • 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
  • Created a utility class that handles the Google authorization code flow

If you haven't done any of things and ended up here via a search engine, I would suggest you start at Part 1 and move forward from there.

What You'll Get out of This

In this part of the series, you will:

  • Revist the Google Cloud Platform to ensure that you have consent set up correctly
  • Create a controller that kicks off the Google authorization code flow process

Once again: only two things. But they'll take you a long way.

Back to the Cloud

Now it's time to revist the Google Cloud Platform. Get thee to this screen (which is where you should be if you click that link):

 

Your screen will look slightly different as your app probably isn't named "Carey Development." But that's fine.

Also: make sure you're on the right project. See that Carey Development in the top blue bar? That's the project I want to work with. Make sure you've got the right project selected as well.

You'll see I've got my Publishing Status set to Testing. That's because I'm still in the infant phase of this process. I'll publish the app later on.

I've also got User Type set to External. That was the only option Google allowed me to select. You probably can't select any other option, either.

Now click Edit App. That will take you to this screen:

 

The App Name field is particularly important. That's because it's the name that gets shown to users when they're asked to grant consent. 

For User support email just put your own Gmail address in there.

Now take a look at the bottom of that page:

 

That's all self-explanatory. I've used careydevelopment.us as my authorized domain for now, but ultimately that domain name needs to be the domain where the Angular app listens for requests.

But in a testing phase, that's fine.

The Developer Contact Information at the bottom is also self-explanatory (and required).

Click SAVE AND CONTINUE. That will take you to this screen:

 

Make sure you see the Gmail API included on that page. If it isn't, then click ADD OR REMOVE SCOPES at the top and add it.

Click SAVE AND CONTINUE. That will take you to this screen:

 

If you don't have a test user set up yet, add yourself. Just click the ADD USERS button and enter your Gmail address.

Make sure that you're logged in to Google with that Gmail address when you begin testing later on.

Click SAVE AND CONTINUE.

Verify that everything's okay on the summary screen and click BACK TO DASHBOARD.

Okay, you're good to go with consent. Now let's get back to coding.

Ground Controller to Major Tom

You've already created a lot of the support classes. Now it's time to create the class that handles receiving new requests for Gmail integration.

Go ahead and call it GmailController. Make it look like this:

@Controller
public class GmailController {

    private static final Logger LOG = LoggerFactory.getLogger(GmailController.class);
    
    @Autowired
    private GoogleOauthUtil googleOauthUtil;
    
    @Autowired
    private AuthorizationUtil authUtil;

    
    @GetMapping("/email/authorizationCode")
    public ResponseEntity<?> getAuthorizationCodeUrl(@RequestParam("redirectUrl") String redirectUrl) {
        User currentUser = authUtil.getCurrentUser();
        
        String url = googleOauthUtil.getAuthorizationCodeUrl(currentUser.getId(), redirectUrl);            
        return ResponseEntity.ok(url);
    }
}

So this first thing you'll notice is that the code autowires a couple of Spring-managed components: GoogleOauthUtil and AuthorizationUtil.

You've already seen GoogleOauthUtil in previous guides. It's what I called "the utility belt."

It's also where the code handles the Google authorization code flow process.

The AuthorizationUtil class includes a couple of convenience methods. You'll see one of those in action in a moment.

The only method in the code snippet above, getAuthorizationCodeUrl(), handles a GET request to the /email/authorizationCode endpoint. That request must include a redirectUrl request parameter.

And that redirectUrl request parameter must match the redirect URL you specified in Google Cloud Platform way back in Part 1 of this series. If you remember, I advised you to set it to http://localhost:4200 for now. You'll need to update it later.

That method starts by getting the User object that represents the current user. It gets that from the getCurrentUser() method of AuthorizationUtil

Then, the code above uses the user's ID to get the authorization code URL. It does that with the assistance of the getAuthorizationCodeUrl() method in the utility belt.

Let's look at that code next.

The URL and You

Here's the relevant code from GoogleOauthUtil

	public String getAuthorizationCodeUrl(String id, String redirectUrl) {		
	    String url = null;
	    
		try {
			AuthorizationCodeRequestUrl acru = getAuthorizationCodeFlow(id).newAuthorizationUrl();
			acru.setRedirectUri(redirectUrl).build();
			//acru.setState("state");
			
			LOG.debug(acru.toString());
			
			url = acru.build();
		} catch (Exception e) {
			LOG.error("Problem getting authorization code!", e);
		}

		return url;
	}

The whole point of that method above is to a return a URL. That's it. That's all it does.

Your application will automagically redirect the user to that URL. It's a Google URL, by the way.

What does it do? It takes the user through the process of granting your application access to his or her Gmail inbox.

So how does it do that? It does that with the assistance of the getAuthorizationCodeFlow() method that you saw in the previous guide.

It uses the object created in that method to generate an authorization URL via the newAuthorizationUrl() method.

That method creates an AuthorizationCodeRequestUrl object. 

But that's not good enough by itself.

That's why the code sets the redirect URL as a property in that AuthorizationCodeRequestUrl object.

Then, it invokes the build() method on that object to create a URL string.

That string gets returned by this method. It's also the string that gets sent back by the getAuthorizationCodeUrl() method in the controller class you saw in the previous section.

Now, a word about that setState() method you see commented out.

In Google API world, you can use the state property to store any value you want. You'll get that exact same thing back as a request parameter (appropriately called "state") in the authorization code URL.

Google says it's a good way to maintain state between your authorization request and the server response.

But it can also be used to mitigate cross-site request forgery attacks. 

That's why I recommend you use it to encode the hash of a cookie or generate a random string. Then, you can validate that response on the client side.

But the code above leaves it alone for testing purposes. Just make sure you update it when you go to production.

Wrapping It Up

Okay I know I said we'd do Postman stuff in this guide but that will happen in the next guide instead.

Yeah. I lied.

I'll do better in the future.

But you've done great if you made it this far. Still a long way to go but you're in good shape.

Have fun!

Photo by Ono Kosuki from Pexels