{"record":{"id":"9544d44544c0ff04","repo":"keycloak/keycloak","slug":"you-must-either-provide-a-permission-ticket-or-the","errorCode":null,"errorMessage":"You must either provide a permission ticket or the permissions you want to request.","messagePattern":"You must either provide a permission ticket or the permissions you want to request\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"authz/client/src/main/java/org/keycloak/authorization/client/util/HttpMethodAuthenticator.java","lineNumber":87,"sourceCode":"\n    public HttpMethod<R> uma() {\n        // if there is an authorization bearer header authenticate using bearer token\n        Header authorizationHeader = method.builder.getFirstHeader(\"Authorization\");\n\n        if (!(authorizationHeader != null && authorizationHeader.getValue().toLowerCase().startsWith(\"bearer\"))) {\n            client();\n        }\n\n        method.params.put(OAuth2Constants.GRANT_TYPE, Arrays.asList(OAuth2Constants.UMA_GRANT_TYPE));\n        return method;\n    }\n\n    public HttpMethod<R> uma(AuthorizationRequest request) {\n        String ticket = request.getTicket();\n        PermissionTicketToken permissions = request.getPermissions();\n\n        if (ticket == null && permissions == null) {\n            throw new IllegalArgumentException(\"You must either provide a permission ticket or the permissions you want to request.\");\n        }\n\n        uma();\n        method.param(\"ticket\", ticket);\n        method.param(\"claim_token\", request.getClaimToken());\n        method.param(\"claim_token_format\", request.getClaimTokenFormat());\n        method.param(\"pct\", request.getPct());\n        method.param(\"rpt\", request.getRptToken());\n        method.param(\"scope\", request.getScope());\n        method.param(\"audience\", request.getAudience());\n        method.param(\"subject_token\", request.getSubjectToken());\n\n        if (permissions != null) {\n            for (Permission permission : permissions.getPermissions()) {\n                String resourceId = permission.getResourceId();\n                Set<String> scopes = permission.getScopes();\n                StringBuilder value = new StringBuilder();\n","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/keycloak/keycloak/blob/66c7e15a3788de7764f07dd2558275a02770e16d/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpMethodAuthenticator.java#L69-L105","documentation":"Thrown by HttpMethodAuthenticator.uma(AuthorizationRequest) as an IllegalArgumentException when both request.getTicket() and request.getPermissions() are null. UMA authorization requires at least one of: a permission ticket obtained from the Protection API, or a set of permissions the client is requesting directly. This is a caller-side precondition failure caught before any HTTP call is made.","triggerScenarios":"Calling new AuthorizationRequest() and passing it to the uma(request) flow (or AuthzClient.authorization(...).authorize(request) with a UMA grant) without ever calling request.setTicket(...) or request.setPermissions(...). It occurs entirely client-side; no network round trip is attempted.","commonSituations":"Migrating from a ticket-based flow to a requesting-party flow and forgetting to populate permissions; building an AuthorizationRequest from a partial DTO/map; copy-paste where setTicket was removed but nothing replaced it; misunderstanding that UMA needs either the ticket (pushed by resource server) or explicit permissions.","solutions":["Before calling uma(), ensure AuthorizationRequest has a ticket: request.setTicket(permissionTicket) obtained from authzClient.protection().permission().create(resource, scopes), OR set permissions: request.setPermissions(new PermissionTicketToken(...)).","Add a guard in your own code: if (request.getTicket() == null && request.getPermissions() == null) throw a clear domain error before calling the client.","If using the resource-server-driven UMA flow, make sure you actually requested a ticket first and wired it into the request."],"exampleFix":"// before\nAuthorizationRequest request = new AuthorizationRequest();\nString rpt = authzClient.authorization().request(rptToken).authorize(); // throws if ticket+permissions null\n\n// after\nAuthorizationRequest request = new AuthorizationRequest();\nPermissionResponse ticketResp = authzClient.protection().permission()\n    .forResource(resourceId).create();\nrequest.setTicket(ticketResp.getTicket());\nString rpt = authzClient.authorization(request).authorize();","handlingStrategy":"validation","validationCode":"// Validate the UMA request before handing it to the client\nAuthorizationRequest req = ...;\nif (req.getTicket() == null && req.getPermissions() == null) {\n    throw new IllegalArgumentException(\n        \"UMA request needs a permission ticket or explicit permissions\");\n}\nauthzClient.authorization(req).authorize();","typeGuard":null,"tryCatchPattern":"try {\n    authzClient.authorization(request).authorize();\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"permission ticket or the permissions\")) {\n        // fix the request: obtain a ticket or set permissions, then retry\n        request.setTicket(obtainTicket());\n        authzClient.authorization(request).authorize();\n    } else throw e;\n}","preventionTips":["Treat ticket/permissions as required fields in any builder/DTO wrapping AuthorizationRequest.","Obtain the permission ticket from the Protection API in the same flow that uses it.","Add a unit test asserting the precondition fires on an empty request."],"tags":["uma","authz-client","validation","permission-ticket"],"backgroundTag":null,"analyzedSha":"66c7e15a3788de7764f07dd2558275a02770e16d","analyzedAt":"2026-08-14T01:36:42.651Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}