Securing Microservices with Auth0 Pt. 3 (Auth Service)
Tags: react, spring, microservices, tutorial
Published: 2019-09-28 20:03:11

This is the third part to a series of posts called Securing Microservices with Auth0. If you missed the [previous post](https://dev.to/bbenefield89/securing-microservices-with-auth0-pt-2-2c23), I would suggest you go back and read that post first.


# Overview

In this part of the **Securing Microservices with Auth0** series, we're going to create the **Auth Service** microservice. The **Auth Services** job is to keep our applications' endpoints secure from any malicious users.

The idea here is that when a user makes a request from the **frontend** to an **endpoint**, sending up an `Authorization: Bearer ${access_token}` header, the request will then be redirected to our **Auth Service** where that **access_token** will be sent to our `/userinfo` endpoint provided to us by [Auth0](https://auth0.com). **Auth0** will attempt to validate the token and if successful our request will then be sent to an endpoint on our **Auth Service** that will finally return a **User** object to our **API** that will eventually return some data back to the **frontend**. Now, that was a lot of information so hopefully, this flowchart will help.

<img src="https://thepracticaldev.s3.amazonaws.com/i/d06jb0z7q5j9ub0weewi.PNG" width="100%" />

You can also go ahead and play around with [the code](https://github.com/bbenefield89/SpringTodo/tree/bbenefield89/tutorial_pt3) for this post. This branch, `bbenefield89/tutorial_pt3`, is the **UI**, **Insecure RESTful API (Resource Service)**, and our **Auth Service**.


# Create the Auth Service

Just like in the last part of this series, I've once again made the decision to go with the [Spring Framework](https://spring.io). You'll soon see how quick and effortless it is to secure your application(s) using **Spring Security**.

Let's head on over to the [Spring Initializr](https://start.spring.io) and like last time, add in the details for your project and pick the libraries you'd like to start with.


### Project Details

<img src="https://thepracticaldev.s3.amazonaws.com/i/htov90t0h40vlqfb6qyu.PNG" width="100%" />


### Libraries

<img src="https://thepracticaldev.s3.amazonaws.com/i/u87fghf41gjf2hyjq9tl.PNG" width="100%" />

Download your project and let's get started.


# Inside our Auth Service

Because we'll eventually have multiple services running we need to make sure that each service uses an open port. Inside of your `application.yml`/`application.properties` go ahead and set your **port** to **8081**.

**application.yml**

```yml
server:
  port: 8081
```


### Create `User` **Model**

Create a new package called `Models` and inside create a new class called `User.java` and insert the following code.

**User.java**
```java
package ${}.${}.TodoApp_Auth.Models;

import lombok.Data;

@Data
public class User {

    private String email;
    private boolean email_verified;
    private String family_name;
    private String given_name;
    private String locale;
    private String name;
    private String nickname;
    private String picture;
    private String sub;
    private String updated_at;

}
```

The **User** class will be used to map the response from `https://auth0Username.auth0.com/userinfo` to an object that will be passed back to your **Resource Service**. Back in our **Resource Service** we will then user the users **email** value to grab **Todos** specific to that user.


### Create `RestInterceptorAll` **Interceptor**

Create a new package called `Interceptor` and inside create a new class called `RestInterceptorAll.java` and insert the following code.

**RestInterceptorAll.java**
```java
package ${}.${}.TodoApp_Auth.Interceptors;

import io.github.bbenefield89.TodoApp_Auth.Models.User;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class RestInterceptorAll extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception {
        /**
         * Wrap the logic of this method in a try/catch
         * If this method fails then we know that something is wrong with the "access_token"
         */
        try {
            HttpHeaders headers = setAuthorizationHeader(req);
            HttpEntity<String> entity = new HttpEntity<>("headers", headers);
            User user = getUserInfoFromAuth0(entity);
            req.getSession().setAttribute("user", user);
            return super.preHandle(req, res, handler);
        } catch (Exception e) {
            // Users "access_token" is wrong so we should notify them that they're unauthorized (401)
            res.setStatus(401, "401 Unauthorized");
            // Return "false" so the "ValidateController" method isn't called
            return false;
        }
    }

    // Sets the "Authorization" header value (Authorization: Bearer ${access_token})
    private HttpHeaders setAuthorizationHeader(HttpServletRequest req) {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", req.getHeader("Authorization"));
        return headers;
    }

    // Sends a GET request grab the users info
    private User getUserInfoFromAuth0(HttpEntity<String> entity) {
        RestTemplate httpRequest = new RestTemplate();
        return httpRequest.exchange(
                "https://bbenefield.auth0.com/userinfo",
                HttpMethod.GET,
                entity,
                User.class
        ).getBody();
    }

}
```


### Create `MvcConfig` **Config**

Create a new package called `Configs` and inside create a new class called `MvcConfig.java` and insert the following code.

**MvcConfig.java**
```java
package ${}.${}.TodoApp_Auth.Configs;

import io.github.bbenefield89.TodoApp_Auth.Interceptors.RestInterceptorAll;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MvcConfig implements WebMvcConfigurer {

    private RestInterceptorAll restInterceptorAll;

    @Autowired
    public MvcConfig(RestInterceptorAll restInterceptorAll) {
        this.restInterceptorAll = restInterceptorAll;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // Registers our "RestInterceptorAll" into the list of global interceptors
        registry.addInterceptor(restInterceptorAll);
    }

}
```


### Create `ValidateController` **Controller**

Create a new package called `Controllers` and inside create a new class called `ValidateController.java` and insert the following code.

**ValidateController.java**
```java
package ${}.${}.TodoApp_Auth.Controllers;

import ${}.${}.TodoApp_Auth.Models.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.SessionAttribute;

@RestController
@RequestMapping("/api/validate")
public class ValidateController {

    // Really simple, if the request makes it this far we can return the "User" object
    @GetMapping
    public User validateUser(@SessionAttribute User user) {
        return user;
    }

}
```


# Manually testing our **Auth Service**

Now that we've written our **Auth Service** we need to make sure things are working.


### Grab an `access_token`

To get an `access_token` you need to start up your frontend and log in as a user. Typically, I just log in through **Google**. To actually get the `access_token` you need to call the `getTokenSilenty()` method that comes from [react-auth0-wrapper.js](https://github.com/bbenefield89/SpringTodo/blob/bbenefield89/tutorial_pt3/todoapp_ui/src/react-auth0-wrapper.js) on the frontend. As an example, you can take a look at my [Profile.js component](https://github.com/bbenefield89/SpringTodo/blob/bbenefield89/tutorial_pt3/todoapp_ui/src/components/Profile.js) in the `test()` method near the bottom of the file.

The `getTokenSilently()` method will return your users `access_token`.


### Test **Auth Service** through **Postman**

After getting the `access_token` make sure you copy it and open up **Postman** and let's make a `GET` request to our **Auth Service**.

**Example Request**

```
GET http://localhost:8081/api/validate

Headers: Authorization: Bearer ${access_token}
```

**Example Response**

```json
{
    "email": "bsquared18@gmail.com",
    "email_verified": true,
    "family_name": "Benefield",
    "given_name": "Brandon",
    "locale": "en",
    "name": "Brandon Benefield",
    "nickname": "bsquared18",
    "picture": "https://lh6.googleusercontent.com/-ASD8&89ASD/photo.jpg",
    "sub": "google-oauth2|9071248919",
    "updated_at": "2019-09-28T18:21:16.685Z"
}
```

If you pass in invalid `access_token` you should receive an empty response with an `HTTP Status 401 Unauthorized`.


# Conclusion

First, give yourself a pat on the back as you've completed the most difficult portion of this series. Security is extremely complicated and takes a long time to wrap your head around so congratulations!

Let's take a look at what you've learned in this post:

- How to write **Interceptors** to intercept a request to a **Controller**

- How to make HTTP requests using **RestTemplate** provided by **Spring**

- How to deny access to an endpoint and return a custom HTTP Status

- How to validate `access_tokens` sent from your frontend

In the next and final post (link coming soon) of this series, we're going to return to our **Resource API** where we will make a request to the API will be presented with a list of Todos from a specific user if they've been properly authenticated.