jsonkeycloakkeycloak-rest-apikeycloak-gatekeeper

How get the client of a composite in Keycloak API


I need to get the clients of the composites of a role in the keycloak API

When I try to get the composite of a role the API returns JSON like this:

{
        "id": "3bb6c58e-17c6-497f-8b7a-1febbc4d2777",
        "name": "role1",
        "description": "test",
        "composite": false,
        "clientRole": true,
        "containerId": "b2ef8aaf-3dc7-44db-8cda-447ee1fccdee"
}

but I don't know which client this role pertences, is there some way to get the client of composites?


Solution

  • This API can get the client's role

    GET http://localhost:8080/admin/realms/${realmName}/clients/${clientId}/roles
    

    If you want to filter only composited roles, filter composite is true.

    {
        id: '<role uuid>',
        name: '<role name>',
        description: '<role description>',
        composite: true,
        clientRole: true,
        containerId: '<client uuid>'
    }
    

    Launch Keycloak by docker compose

    In here

    Demo

    demo.js

    const axios = require('axios');
    
    const getMasterToken = async (userName, password) => {
        try {
            const resp = await axios.post(
                'http://localhost:8080/realms/master/protocol/openid-connect/token',
                new URLSearchParams({
                    'client_id': 'admin-cli',
                    'username': userName,
                    'password': password,
                    'grant_type': 'password'
                })
            );
            return resp.data.access_token;
        } catch (err) {
            console.error(err);
        }
    };
    
    const getClients = async (token, realmName) => {
        try {
            const config = {
                headers: { Authorization: `Bearer ${token}` }
            };
            const url = `http://localhost:8080/admin/realms/${realmName}/clients/`;
            const response = await axios.get(url, config);
    
            if (response.status === 200) {
                return response.data;
            } else {
                console.error(`Failed to fetch client: Server responded with status ${response.status}`);
                return null;
            }
        } catch (error) {
            if (error.response) {
                console.error('Server responded with status:', error.response.status, 'Response data:', error.response.data);
            } else if (error.request) {
                console.error('No response received:', error.request);
            } else {
                console.error('Error setting up request:', error.message);
            }
            return null;
        }
    };
    const getClient = async (token, realmName, clientName) => {
        try {
            const config = {
                headers: { Authorization: `Bearer ${token}` }
            };
            const url = `http://localhost:8080/admin/realms/${realmName}/clients/?clientId=${clientName}`;
            const response = await axios.get(url, config);
    
            if (response.status === 200) {
                return response.data;
            } else {
                console.error(`Failed to fetch client: Server responded with status ${response.status}`);
                return null;
            }
        } catch (error) {
            if (error.response) {
                console.error('Server responded with status:', error.response.status, 'Response data:', error.response.data);
            } else if (error.request) {
                console.error('No response received:', error.request);
            } else {
                console.error('Error setting up request:', error.message);
            }
            return null;
        }
    };
    
    const getClientRoles = async (token, realmName, clientId, isComposite) => {
        try {
            const config = {
                headers: {
                    Authorization: `Bearer ${token}`
                }
            };
            const url = `http://localhost:8080/admin/realms/${realmName}/clients/${clientId}/roles`;
            const response = await axios.get(url, config);
    
            if (response.status === 200 && Array.isArray(response.data)) {
                const roles = response.data.filter(r => typeof r.composite === 'boolean' && r.composite === isComposite);
                return roles.length > 0 ? roles : null; // Return the filtered roles if any, otherwise null
            } else {
                console.error(`Failed to fetch roles: Server responded with status ${response.status}`);
                return null;
            }
        } catch (error) {
            if (error.response) {
                console.error('Server responded with status:', error.response.status, 'Response data:', error.response.data);
            } else if (error.request) {
                console.error('No response received:', error.request);
            } else {
                console.error('Error setting up request:', error.message);
            }
            return null;
        }
    };
    
    (async () => {
    
        const masterToken = await getMasterToken('admin', 'admin');
        const realmName = 'my-realm';
    
        const clients = await getClients(masterToken, realmName);
    
        for (const client of clients) {
            const clientName = client.clientId;
            const clientData = await getClient(masterToken, realmName, clientName);
            const clientId = (clientData) ? clientData[0].id : null;
        
            const roles = await getClientRoles(masterToken, realmName, clientId, true);
            if (roles) {
                console.log(`Client Name: ${clientName}, Client ID: ${clientId}`);
                console.log(roles , '\n');
            }
        }
    })();
    

    Install Dependency

    npm install axios
    

    Run it

    node demo.js
    

    Result

    Client Name: account, Client ID: c9f454f2-a111-4d47-850f-69a10f8f1691
    [
      {
        id: '7e219a18-5a7d-4e9a-803e-4ccefa9802a8',
        name: 'manage-consent',
        description: '${role_manage-consent}',
        composite: true,
        clientRole: true,
        containerId: 'c9f454f2-a111-4d47-850f-69a10f8f1691'
      },
      {
        id: '72c57d15-02cb-4fbe-99e1-f815ad12b9de',
        name: 'manage-account',
        description: '${role_manage-account}',
        composite: true,
        clientRole: true,
        containerId: 'c9f454f2-a111-4d47-850f-69a10f8f1691'
      }
    ]
    
    Client Name: realm-management, Client ID: f9cdff68-ce98-4112-b6c1-acacbd73dcfc
    [
      {
        id: 'a69862d5-1ecc-4dc7-b223-78a4429c7778',
        name: 'realm-admin',
        description: '${role_realm-admin}',
        composite: true,
        clientRole: true,
        containerId: 'f9cdff68-ce98-4112-b6c1-acacbd73dcfc'
      },
      {
        id: '23aedd8c-4a1e-4506-a8a9-681cde8b9c8c',
        name: 'view-clients',
        description: '${role_view-clients}',
        composite: true,
        clientRole: true,
        containerId: 'f9cdff68-ce98-4112-b6c1-acacbd73dcfc'
      },
      {
        id: '8eae6bb1-4424-4cff-a09e-bab7304d8be4',
        name: 'view-users',
        description: '${role_view-users}',
        composite: true,
        clientRole: true,
        containerId: 'f9cdff68-ce98-4112-b6c1-acacbd73dcfc'
      }
    ]
    

    enter image description here