{"record":{"id":"12a958cc95d26971","repo":"quarkusio/quarkus","slug":"only-user-bob-is-allowed-to-request-roles","errorCode":null,"errorMessage":"Only user 'bob' is allowed to request roles","messagePattern":"Only user 'bob' is allowed to request roles","errorType":"http","errorClass":"ForbiddenException","httpStatus":403,"severity":"error","filePath":"integration-tests/smallrye-jwt-token-propagation/src/main/java/io/quarkus/it/keycloak/RolesResource.java","lineNumber":24,"sourceCode":"\nimport org.eclipse.microprofile.jwt.JsonWebToken;\n\nimport io.quarkus.security.Authenticated;\nimport io.quarkus.security.ForbiddenException;\n\n@Path(\"/roles\")\n@Authenticated\npublic class RolesResource {\n\n    @Inject\n    JsonWebToken jwt;\n\n    @GET\n    public String get() {\n        if (\"alice\".equals(jwt.getName())) {\n            return \"tester\";\n        }\n        throw new ForbiddenException(\"Only user 'bob' is allowed to request roles\");\n    }\n}\n","sourceCodeStart":6,"sourceCodeEnd":27,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/integration-tests/smallrye-jwt-token-propagation/src/main/java/io/quarkus/it/keycloak/RolesResource.java#L6-L27","documentation":"RolesResource.get returns the 'tester' role only for the authenticated user 'alice'; for any other caller (e.g. 'bob') it throws a Jakarta REST ForbiddenException, which Quarkus maps to HTTP 403. Despite the message text, the check actually permits only alice — the message is misleading.","triggerScenarios":"Calling GET on the roles endpoint while authenticated as any user other than 'alice' (jwt.getName() != 'alice').","commonSituations":"Testing JWT token propagation with Keycloak where a test token for 'bob' or another principal hits the endpoint; misconfigured Keycloak client mapping that yields the wrong preferred_username.","solutions":["Send a JWT whose subject/name is 'alice' when calling this endpoint","Fix the misleading message or the condition — if 'bob' should be allowed, change the guard to accept bob","Verify your token issuer/claims configuration so the expected principal name is present"],"exampleFix":"// before\nthrow new ForbiddenException(\"Only user 'bob' is allowed to request roles\");\n// after\nif (\"alice\".equals(jwt.getName()) || \"bob\".equals(jwt.getName())) {\n    return \"tester\";\n}\nthrow new ForbiddenException(\"Only user 'alice' is allowed to request roles\");","handlingStrategy":"try-catch","validationCode":"// client-side: inspect the token principal before calling\nif (!\"alice\".equals(jwt.getClaim(\"preferred_username\"))) {\n    // use a token for 'alice' or expect 403\n}\n","typeGuard":null,"tryCatchPattern":"try {\n    String role = rolesResource.get();\n} catch (ForbiddenException e) {\n    // HTTP 403: token principal is not 'alice'; refresh token or switch user\n}","preventionTips":["Check jwt.getName() expectations against your Keycloak token mapper config","Never rely on exception messages for logic — this one names 'bob' but the code checks 'alice'","Write tests per principal (alice, bob, anonymous) to catch guard mismatches"],"tags":["jwt","security","resteasy","forbidden"],"backgroundTag":"jwt-forbidden-principal","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}