📒
openid-connect-workshop
  • Introduction
  • Introduction
    • Requirements and Setup
    • Sample Application Architecture
  • Intro Labs
    • Authorization Grant Flows in Action
    • Authorization Code Grant Demo
    • GitHub Client
  • Hands-On Labs
    • Resource Server
    • Client (Authorization Code Flow)
    • Client (Client Credentials Flow)
    • Testing JWT Auth&Authz
    • JWT Testing Server
    • SPA Client (Authz Code with PKCE)
  • Bonus Labs​
    • Multi-Tenant Resource Server
    • Micronaut
    • Quarkus
    • Keycloak Testcontainers
Powered by GitBook
On this page
  • Lab Contents
  • REST API
  • Users and roles

Was this helpful?

  1. Bonus Labs​

Micronaut

PreviousMulti-Tenant Resource ServerNextQuarkus

Last updated 4 years ago

Was this helpful?

In this bonus lab we'll see how a Microservice can be extended to an OAuth 2.0 and OpenID Connect 1.0 compliant Resource Server.

See for all details on how to build and configure a resource server requiring JWT bearer tokens.

Lab Contents

REST API

This Micronaut demo app just provides one secured endpoint at .

To test if the application works as expected, either

  • open Postman and configure request for

  • or use a command line like curl, httpie or postman (if you like a UI)

Httpie:

http localhost:9096/hello

Curl:

curl http://localhost:9096/hello

At this stage the application will return a 401 status.

Users and roles

As this app uses the same Keycloak client configuration you can just use the same users as before:

Username

Email

Password

Role

bwayne

bruce.wayne@example.com

wayne

LIBRARY_USER

bbanner

bruce.banner@example.com

banner

LIBRARY_USER

pparker

peter.parker@example.com

parker

LIBRARY_CURATOR

ckent

clark.kent@example.com

kent

LIBRARY_ADMIN

Step 1: Generate the application

mn create-app micronaut-server-app

Step 2: Add dependencies

To extend a Micronaut application into a resource server you have to make sure the following dependencies are in the gradle build file build.gradle:

annotationProcessor("io.micronaut.security:micronaut-security-annotations")
implementation("io.micronaut.security:micronaut-security-jwt")

Step 3: Add jwt configuration

Micronaut requires a JWKS to validate a JWT token signature. This is why Micronaut requires to configure a jwks_uri entry in application.yaml:

micronaut:
  security:
    authentication: bearer
    token:
      roles-name: 'groups'
      jwt:
        enabled: true
        signatures:
          jwks:
            keycloak:
              url: 'http://localhost:8080/auth/realms/workshop/protocol/openid-connect/certs'

An error you get very often with files in yaml format is that the indents are not correct. This can lead to unexpected errors later when you try to run all this stuff.

With this configuration in place we have already a working resource server that can handle JWt access tokens transmitted via http bearer token header. Micronaut also validates by default:

  • the JWT signature against the queried public key(s) from jwks_url

  • that the JWT is not expired

In addition, Micronaut automatically maps all 'groups' claim entries to corresponding roles that may be checked via @Secured annotations.

Step 4: Secure the endpoint

Look into the class micronaut.server.app.HelloController to see how the only REST endpoint is secured and the details of the JWT based principal are read and returned:

package micronaut.server.app;

import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.security.annotation.Secured;
import io.micronaut.security.authentication.Authentication;

import java.util.Map;

@Secured("isAuthenticated()")
@Controller("/hello")
public class HelloController {

    @Get
    public String sayHello(Authentication authentication) {
        Map<String, Object> claims = authentication.getAttributes();
        return "it works for user: " + claims.get("name") + " (" + claims.get("email") + ")";
    }
}

Step 5: Run and test basic resource server

Before starting the Micronaut application please make sure that the annotation processing is enabled for the java compiler in your IDE.

Now it should be possible to start the configured application micronaut.server.app.MicronautServerApp.

Again we use the password grant flow request to get a token for calling our new service:

httpie:

http --form http://localhost:8080/auth/realms/workshop/protocol/openid-connect/token grant_type=password \
username=ckent password=kent client_id=library-client client_secret=9584640c-3804-4dcd-997b-93593cfb9ea7

curl:

curl -X POST -d 'grant_type=password&username=ckent&password=kent&client_id=library-client&client_secret=9584640c-3804-4dcd-997b-93593cfb9ea7' \
http://localhost:8080/auth/realms/workshop/protocol/openid-connect/token

This should return an access token together with a refresh token:

```http request HTTP/1.1 200 OK Content-Type: application/json

{ "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgO...", "expires_in": 300, "not-before-policy": 1556650611, "refresh_expires_in": 1800, "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIg...", "scope": "profile email user", "session_state": "c92a82d1-8e6d-44d7-a2f3-02f621066968", "token_type": "bearer" }

To make the same request again to the _hello' endpoint (like in the beginning of this lab) we have to
specify the access token as part of a _Authorization_ header of type _Bearer_ like this:

httpie:

```bash
http localhost:9096/hello \
'Authorization: Bearer [access_token]'

curl:

curl -H 'Authorization: Bearer [access_token]' \
-v http://localhost:9096/hello | jq

You should now see something like this:

HTTP/1.1 200 OK
Date: Mon, 21 Oct 2019 18:24:17 GMT
connection: keep-alive
content-length: 54
content-type: application/json

it works for user: Clark Kent (clark.kent@example.com)

We will use as identity provider. Please again make sure you have set up and running keycloak as described in

This application has been generated using the :

This concludes the .

Keycloak
Setup Keycloak
Micronaut cli generator tool
Bonus Lab
Micronaut
Micronaut JWT Security Guide
localhost:9096/hello
localhost:9096/hello
Step 1: Generate the application
Step 2: Add required extra dependencies
Step 3: Configure JWT authentication and token validation
Step 4: Secure the endpoint
Step 5: Run the application