Introduction

This tutorial provides a step-by-step guide on securing a Quarkus backend application using IBM App ID.

Configure IBM App ID

Login to IBM Cloud and create an App ID instance using the lite (free) plan.

0-new-appid

Then create an application as a regular web app. Next, create a test user using Cloud Directory -> Users menu.

1-add-user

Configure Quarkus

First, update Maven pom.xml :

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-oidc</artifactId>
</dependency>

Next, find the client ID/secret/login URL in IBM App id application details:

2-app-config

And then enter them into application.properties :

quarkus.oidc.auth-server-url=https://eu-de.appid.cloud.ibm.com/oauth/v4/xxxx-0839-463f-a816-22ba90f44ee2
quarkus.oidc.client-id=xxxx-40d0-486d-af5f-16e2a4c4f837
quarkus.oidc.credentials.secret=xxxxMzhkMGQ2

Next, add some resources that need authentication, like the one bellow:

package org.acme.rest.json;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

import org.eclipse.microprofile.jwt.Claims;
import org.eclipse.microprofile.jwt.JsonWebToken;
import org.jboss.resteasy.reactive.NoCache;

import io.quarkus.security.Authenticated;
import io.quarkus.security.identity.SecurityIdentity;


@Path("/api/users")
@Authenticated
public class UsersResource {

    @Inject
    SecurityIdentity securityIdentity;

    @Inject
    JsonWebToken accessToken;

    @GET
    @Path("/me")
    @NoCache
    public User me() {
        return new User(securityIdentity);
    }

    public static class User {

        private final String userName;

        User(SecurityIdentity securityIdentity) {
            this.userName = securityIdentity.getPrincipal().getName();
        }

        public String getUserName() {
            return userName;
        }
    }

}

Test the application

First, run the quarkus app using:

./mvnw quarkus:dev

Then, get a token using curl command and replacing the <useremail>/<password> with the above username and password. Also, replace <auth> with the Base64-encoded string of the application clientid:secret .

curl -X POST "https://eu-de.appid.cloud.ibm.com/oauth/v4/XXXX-0839-463f-a816-22ba90f44ee2/token" -H "Authorization: Basic <auth>" -H "Accept: application/json" -F "grant_type=password" -F "username=<useremail>" -F "password=<password>"

The response should look like the one bellow:

{
  "access_token": "xxxx,
  "id_token": "yyyy",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "openid appid_default appid_readuserattr appid_readprofile appid_writeuserattr appid_authenticated"
}

The access_token is the one you need for backend access. By default, it looks like:

Header:
{
   "alg": "RS256",
   "typ": "JWT",
   "kid": "appId-39a37f57-a227-4bfe-a044-93b6e6050a61-2018-08-02T11:57:43.401",
   "ver": 4
}
Payload:
{
   "iss": "https://us-south.appid.cloud.ibm.com/oauth/v4/39a37f57-a227-4bfe-a044-93b6e6050a61",
   "exp": 1551903163,
   "aud": [
   "968c2306-9aef-4109-bc06-4f5ed6axi24a"
   ],
   "sub": "2b96cc04-eca5-4122-a8de-6e07d14c13a5",
   "email_verified": true,
   "amr": [
   "cloud_directory"
   ],
   "iat": 1551899553,
   "tenant": "39a37f57-a227-4bfe-a044-93b6e6050a61",
   "scope": "openid appid_default appid_readprofile appid_readuserattr appid_writeuserattr appid_authenticated"
}

The id_token is a token that contains information about the user. By default, it looks like:

Header:
{
   "alg": "RS256",
   "typ": "JWT",
   "kid": "appId-39a37f57-a227-4bfe-a044-93b6e6050a61-2018-08-02T11:57:43.401",
   "ver": 4
}
Payload:
{
   "iss": "https://us-south.appid.cloud.ibm.com/oauth/v4/39a37f57-a227-4bfe-a044-93b6e6050a61",
   "aud": [
   "968c2306-9aef-4109-bc06-4f5ed6axi24a"
   ],
   "exp": 1551903163,
   "tenant": "39a37f57-a227-4bfe-a044-93b6e6050a61",
   "iat": 1551899553,
   "email": "appid155@mailinator.com",
   "name": "appid155@mailinator.com",
   "sub": "2b96cc04-eca5-4122-a8de-6e07d14c13a5",
   "email_verified": true,
   "identities": [
   {
      "provider": "cloud_directory",
      "id": "118c0278-3526-4954-876b-cf70eb88efa2"
   }
   ],
   "amr": [
   "cloud_directory"
   ]
}

Now, finaly let’s call out api usign a command similar the this one:

curl -v -X GET "http://127.0.0.1:8080/api/users/email" -H "Authorization: Bearer <token>"

If everything it’s ok, you shoud receive the user id as response.

{"userName":"XXXX-15dc-4103-a604-66265c439c73"}