Obtaining Permissions by pushing claims from Backend by using AccessToken from frontend (reactSPA) #35310

Keycloak Authorization: Obtaining Permissions

Question: Can backend client use “Access Token” obtained by “frontend” client and use it to ‘authorization check’ (Keycloak Policies) and pass “claim_token” in it? For me it returns
error: “Public clients are not allowed to send claims”

I understand Keycloak’s concern from error message. It is not allowing any public client to push any arbitrary attributes to keycloak. This makes sense to me. But, why keycloak is treating this request is coming from “public client”? Is it because “azp” in AcccessToken is set to “frontend-client” (client_id)? How can we ensure Keycloak that this request is actually from “backend” and it is OK to allow this.

How can ‘backend client’ do authorization using ‘Access Token’? Providing this ‘Access Token’ is also important as Keycloak Policies will then do other checks like: roles, groups, etc. based on what is inside claims of AccessToken.

Note: Without “claim_token”, this request succeds and I am able to test “postivie” and “negative” test cases for different users in keycloak using keycloak policies. This works so well.

I think I am missing something here.

Code:

  keycloak_openid = KeycloakOpenID(server_url=SERVER_URL,
                                    realm_name=REALM_NAME,
                                    client_id=BACKEND_CLIENT_ID,
                                    client_secret_key=CLIENT_SECRET)
   token = keycloak_openid.token(username=username,
                                 password=password)
   r = Resource(resource=resource)
   s = Scope(scope=scope)
   permission = r(s)
   print(f"Resource and Scope: {permission}")
   permissions = [permission]
   auth_url = "https://localhost:8443/realms/test-realm/protocol/openid-connect/token"
   claim_token_data = {
       "organization_id": ["123456", "895743"],
       "user_organization_id": ["98761", "93658"],
   }
   claim_token = get_additional_claim_token(claim_token_data)
   payload = {
       "grant_type": "urn:ietf:params:oauth:grant-type:uma-ticket",
       "permission": ",".join(str(permission) for permission in permissions),
       "response_mode": "decision",
       "audience": BACKEND_CLIENT_ID,
       "claim_token_format": "urn:ietf:params:oauth:token-type:jwt",
       "claim_token": claim_token,
   }
   headers = {
       "Authorization": "Bearer " + token['access_token'],
       "Content-Type": "application/x-www-form-urlencoded",
   }
   response = _send_request("post",
                            url=auth_url,
                            data=payload,
                            headers=headers)

Did you try a token-exchange in the backend first ( exchange the FE token for a BE token) ?

And your code does not use the FE token as you use direct grant (aka as username/password) from the BE?