Managing JWT Auth with Micronaut v2 (Part 3)

Ruben Mondejar
4 min readApr 18, 2020

In this third part of this particular trilogy on Micronaut v2, we are going to finish our project by deploying our new backend, which given a valid token provides user-related data thought a protected REST API.

Previously

In the previous parts, we followed the steps to build our backend implementation, resulting in a secured API that allows users to sign-up and sign-in (Part1) to finally retrieve user-related data using the JWT access token (Part 2).

Open API

Before reaching the cloud topic, let’s prepare our project to be more documented for future integrations, providing an easy way to use our API.

  1. Swaggerizing our project implies adding a few dependencies :
annotationProcessor "io.micronaut.configuration:micronaut-openapi"
implementation "io.swagger.core.v3:swagger-annotations"

2. Specifying the basic info of our API thought annotations on our main class :

@OpenAPIDefinition(info = @Info(title = "mn-jwt-jpa",             
version = "0.3"))
public class Application {
public static void main(String[] args) {
Micronaut.run(Application.class);
}
}

3. Lastly, we need to change our routing to be able to reach these statically generated resources, and we need to open the security in this URL as well:

micronaut:
router:
static-resources:
swagger:
paths: classpath:META-INF/swagger
mapping: /swagger/**
security:
enabled: true
interceptUrlMap:
- pattern: "/swagger/**"
httpMethod: GET
access:
- isAnonymous()

4. And that’s it, our API is ready to be consumed in the corresponding URL: http://localhost:8080/swagger/mn-jwt-jpa-0.3.yml

Google Cloud Run

Now is time to deal with the Cloud provider, in this case, Google Cloud.

  1. First, we need to update our project configuration into the build.gradle by adding the jib plugin.
plugins {
(...)
id "com.google.cloud.tools.jib" version "2.1.0"
}

ext {
googleProjectId= "myGoogleProjectId"
(...)
}

(...)

jib {
to { image = "gcr.io/$googleProjectId/mn-jwt-data" }
from {
image = "adoptopenjdk/openjdk11-openj9:jdk-11.0.1.13-alpine-slim"
}
container {
jvmFlags = ['-XX:TieredStopAtLevel=1','-XX:MaxRAM=128m']
}
}

2. We are going to use the Google Cloud Platform to take advantage of the awesome support that Micronaut provides. To accomplish this task, just follow the next steps carefully:

A. Follow the Google Cloud instructions in order to obtain your project ID

B. Install Docker locally https://www.docker.com/get-started

C. And, be sure you didn’t miss any step, and you are now able to deploy your Docker image into Google Container Registry

Now your local machine is ready to go.

Deployment

At this point, we can deploy our backend image into the cloud platform, and access it remotely. Lucky us, only a few commands that are required to perform this final action.

  1. First, we need to push the image to the Container Registry:
$ ./gradlew jib

2. And now, deployment is as simple as running:

$ gcloud beta run deploy --image gcr.io/my-project/mn-jwt-data

3. Hopefully, the outcome is something similar to this:

Deploying container to Cloud Run service [mn-jwt-data] in project my-project region [us-central1]✓ Deploying... Done.                                                                                                                                                                                                            
✓ Creating Revision...
✓ Routing traffic...
Done.

Service [mn-jwt-data] revision [mn-jwt-data-00004] has been deployed and is serving traffic at https://mn-jwt-data-9823r98652-uc.a.run.app

At this point, we have our service running on Google Cloud and we can use our new URL to verify that everything is done.

Playing with it

Finally, let’s create and recover data from our remote backend to demonstrate it works as expected and it is ready to go:

  1. Checking the API remotely
https://mn-jwt-data-9823r98652-uc.a.run.app/swagger/mn-jwt-jpa-0.3.ymlopenapi: 3.0.1
info:
title: mn-jwt-jpa
version: "0.3"
paths:
/messages/all:
get:
(...)
/messages:
get:
(...)
post:
(...)
/signup:
post:
(...)
components:
schemas:
MessageDto:
(...)
UserDto:
(...)

2. Create a new user

$ curl -d '{"username":"foo", "password":"bar"}' 
-H "Content-Type: application/json"
-X POST https://mn-jwt-data-9823r98652-uc.a.run.app/signup
{“username”:“foo”, “password”: “bar”}

3. Login with the user

$ curl -d '{"username":"foo", "password":"bar"}' 
-H "Content-Type: application/json"
-H "Authorization: Basic dXNlcjE6cGFzc3dvcmQx"
-X POST https://mn-jwt-data-9823r98652-uc.a.run.app/login
{"username":"foo",
"roles":["VIEW"],
"access_token":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJmb28iLCJuYmYiOjE1ODcyMDI1NTksInJvbGVzIjpbIlZJRVciXSwiaXNzIjoibW4tand0LWRhdGEiLCJleHAiOjE1ODcyMDYxNTksImlhdCI6MTU4NzIwMjU1OX0.KCRegv1hbceK4a2SgeOtim3dlaVtaaZ67FKMJQk6_3Y",
(...),
"token_type":"Bearer",
"expires_in":3600}

4. Create messages bound to our user

$ curl -d "'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'" 
-H "Content-Type: application/json"
-H "'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJmb28iLCJuYmYiOjE1ODcyMDI1NTksInJvbGVzIjpbIlZJRVciXSwiaXNzIjoibW4tand0LWRhdGEiLCJleHAiOjE1ODcyMDYxNTksImlhdCI6MTU4NzIwMjU1OX0.KCRegv1hbceK4a2SgeOtim3dlaVtaaZ67FKMJQk6_3Y'"
-X POST https://mn-jwt-data-9823r98652-uc.a.run.app/messages
{"id": 1,
"content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
"creationDate": [2020,4,18],
"username": "foo"}

5. Finally, recover messages from our user

$ curl 
-H "'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJmb28iLCJuYmYiOjE1ODcyMDI1NTksInJvbGVzIjpbIlZJRVciXSwiaXNzIjoibW4tand0LWRhdGEiLCJleHAiOjE1ODcyMDYxNTksImlhdCI6MTU4NzIwMjU1OX0.KCRegv1hbceK4a2SgeOtim3dlaVtaaZ67FKMJQk6_3Y'"
-X GET https://mn-jwt-data-9823r98652-uc.a.run.app/messages
[{"id": 1,
"content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
"creationDate": [2020,4,18],
"username": "foo"}
}]

Final Thoughts

Congratulations! now you are ready to expand your API, integrate external services, divide this backend into different subprojects or microservices, configure K8s, implement other cloud mechanisms, or whatever you need for your project, have fun!

P.S.: Remember that you can find the final project here: https://github.com/rmondejar/mn-jwt-data

--

--

Ruben Mondejar

Director of Engineering at @getuberall . Childhood with puzzles, Lego, and MSX. PhD, Passionate Dev, and Proud Father