3

I am having issues with decoding/using/verifying the passed JWT to my Java EE 8 with MicroProfile 2.0.1 backend running on Payara 5.183. The React frontend application passes the JWT token, which is obtained from Keycloak, to the backend as Authorization: Bearer eyXJS... The backend is configured to verify the JWT token as defined in the MicroProfile JWT Auth Spec 1.1 with the following microprofile-config.properties in src/main/resources/META-INF:

mp.jwt.verify.publickey.location=/META-INF/orange.pem
mp.jwt.verify.issuer=http://localhost:8282/auth/realms/MicroProfile

and the public key from Keycloak is stored in the orange.pem file. The JAX-RS configuration looks like the following:

@LoginConfig(authMethod = "MP-JWT")
@ApplicationPath("resources")
public class JAXRSConfiguration extends Application {

}

and I am trying to use the JWT in one of the endpoints:

@Path("secure")
@Stateless
public class VerySecureResource {

    @Inject
    @ConfigProperty(name = "message")
    private String message;

    @Inject
    private JsonWebToken callerPrincipal;

    @GET
    public Response message() {

        System.out.println(callerPrincipal.getIssuer());
        System.out.println(callerPrincipal.getRawToken());
        System.out.println(callerPrincipal.getTokenID());

        return Response.ok(callerPrincipal.getName() + " is allowed to read message: " + message).build();
    }

}

The application deploys without any error and I don't get any logging information within the server.log of Payara regarding a failed JWT verification. I even turned on the logging for fish.payara.microprofile.jwtauth.

[2018-12-26T17:06:20.835+0100] [Payara 5.183] [INFORMATION] [] [org.glassfish.soteria.servlet.SamRegistrationInstaller] [tid: _ThreadID=196 _ThreadName=admin-thread-pool::admin-listener(6)] [timeMillis: 1545840380835] [levelValue: 800] [[
  Initializing Soteria 1.1-b01 for context '/microprofile-jwt-keycloak-auth']]

[2018-12-26T17:06:20.841+0100] [Payara 5.183] [INFORMATION] [] [fish.payara.microprofile.jwtauth.servlet.RolesDeclarationInitializer] [tid: _ThreadID=196 _ThreadName=admin-thread-pool::admin-listener(6)] [timeMillis: 1545840380841] [levelValue: 800] [[
  Initializing MP-JWT 5.183 for context '/microprofile-jwt-keycloak-auth']]

[2018-12-26T17:06:20.933+0100] [Payara 5.183] [INFORMATION] [AS-WEB-GLUE-00172] [javax.enterprise.web] [tid: _ThreadID=196 _ThreadName=admin-thread-pool::admin-listener(6)] [timeMillis: 1545840380933] [levelValue: 800] [[
  Loading application [microprofile-jwt-keycloak-auth] at [/microprofile-jwt-keycloak-auth]]]

[2018-12-26T17:06:20.949+0100] [Payara 5.183] [INFORMATION] [] [javax.enterprise.system.core] [tid: _ThreadID=196 _ThreadName=admin-thread-pool::admin-listener(6)] [timeMillis: 1545840380949] [levelValue: 800] [[
  microprofile-jwt-keycloak-auth was successfully deployed in 954 milliseconds.]]

[2018-12-26T17:06:26.428+0100] [Payara 5.183] [INFORMATION] [] [] [tid: _ThreadID=42 _ThreadName=http-thread-pool::http-listener-1(3)] [timeMillis: 1545840386428] [levelValue: 800] [[
  null]]

[2018-12-26T17:06:26.428+0100] [Payara 5.183] [INFORMATION] [] [] [tid: _ThreadID=42 _ThreadName=http-thread-pool::http-listener-1(3)] [timeMillis: 1545840386428] [levelValue: 800] [[
  null]]

[2018-12-26T17:06:26.428+0100] [Payara 5.183] [INFORMATION] [] [] [tid: _ThreadID=42 _ThreadName=http-thread-pool::http-listener-1(3)] [timeMillis: 1545840386428] [levelValue: 800] [[
  null]]

The decoded JWT looks like the following:

{
    "jti": "5a3c600e-95ea-41cb-8e65-8342a3b867bc",
    "exp": 1545840603,
    "nbf": 0,
    "iat": 1545840303,
    "iss": "http://localhost:8282/auth/realms/MicroProfile",
    "aud": "account",
    "sub": "f2a492cb-cf9f-46ac-8f04-941601c6574b",
    "typ": "Bearer",
    "azp": "react-webapp",
    "nonce": "f650eb68-611f-4bd9-97a7-d07f1b3e29de",
    "auth_time": 1545840302,
    "session_state": "f6627b25-b089-4234-b25c-bffa67a9a8f7",
    "acr": "1",
    "allowed-origins": [
        "http://localhost:3000"
    ],
    "realm_access": {
        "roles": [
            "offline_access",
            "uma_authorization",
            "USER"
        ]
    },
    "resource_access": {
        "account": {
            "roles": [
                "manage-account",
                "manage-account-links",
                "view-profile"
            ]
        }
    },
    "scope": "openid profile email",
    "email_verified": false,
    "name": "duke duke",
    "groups": [
        "/USER"
    ],
    "preferred_username": "duke",
    "given_name": "duke",
    "family_name": "duke",
    "email": "duke@jakarta.ee"
}

The whole codebase is available on GitHub

rieckpil
  • 10,470
  • 3
  • 32
  • 56
  • Can you indicate which public key from KeyCloak you have put into orange.pem.? Is it the public key of the RSA key of the realm? Can you verify in the header that the keyId matches the id defined of the RSA key in the realm. (and that you specified RSA256 in Signature algorithm of the tokens config) – Rudy De Busscher Jan 03 '19 at 05:57
  • Yes I verified the RSA signature with https://jwt.io/ it's the public key of my realm – rieckpil Jan 03 '19 at 06:22
  • What HTTP status do you get back? 401, 403, 200? – Rudy De Busscher Jan 04 '19 at 11:09
  • If the JAX-RS endpoint is secured I'll get 401 – rieckpil Jan 05 '19 at 07:33

1 Answers1

4

I saw that you just added the @LoginConf annotation on the JAX-RS application, but that is not enough for the resources to be protected.

It is a kind of marker that all protected endpoints will be using the JWT from the Authentication header.

So you need to define the endpoint as

@GET
@RolesAllowed("/USER")
public Response message() {

Only then the authentication from the JWT will kick in.

You need to declare all the roles in web.xml or with the DeclaresRoles on Application bean (or any other CDI bean)

@ApplicationPath("/data")
@LoginConfig(authMethod = "MP-JWT")
@DeclareRoles({"/USER"})
public class Keycloack_jwtRestApplication extends Application {
  • I wonder if line `@LoginConfig(authMethod = "MP-JWT")` is required anymore? I.e., can you leverage `JsonWebToken` with `@RolesAllowed` but without `@LoginConfig`? – oneturkmen Oct 20 '21 at 17:58
  • 1
    The current version of the MicroProfile JWT specification still requires the usage of @LoginConfig(authMethod = "MP-JWT") – Rudy De Busscher Oct 22 '21 at 06:39