25

I know that there is admin APIs to get the list of users which returns the user representation array.

GET /admin/realms/{realm}/groups/{id}/members

returns

https://www.keycloak.org/docs-api/2.5/rest-api/index.html#_userrepresentation

but is there a way to get users by custom attribute ?

Milan Savaliya
  • 500
  • 1
  • 6
  • 12

6 Answers6

20

This is enabled out of the box from Keycloak version 15.1.0

Using GET /{realm}/users API, parameter q is introduced: A query to search for custom attributes, in the format 'key1:value2 key2:value2'

curl 'http://{{keycloak_url}}/auth/admin/realms/{{realm}}/users?q=phone:123456789'

You can also combine several attributes within this parameter using space ' ' delimiter

curl 'http://{{keycloak_url}}/auth/admin/realms/{{realm}}/users?q=phone:123456789 country:USA'

Docs: https://www.keycloak.org/docs-api/15.1/rest-api/index.html#_users_resource

Darko
  • 201
  • 2
  • 2
18

This is not possible by default, but Keycloak offers the possibility to extend its functionalities via a system of Service Provider Interfaces which is very easy to implement.

Here is an example of new route that allows to search by custom attributes :

public class SearchByAttributeResourceProvider implements RealmResourceProvider {
    private KeycloakSession session;

    public SearchByAttributeResourceProvider(KeycloakSession session) {
        this.session = session;
    }

    @Override
    public Object getResource() {
        return this;
    }

    @GET
    @Path("search-by-stuff/{stuffValue}")
    @Produces({MediaType.APPLICATION_JSON})
    public List<UserRepresentation> getUsersByStuff(@PathParam("stuffValue") String stuffValue) {
        return session
                .users()
                .searchForUserByUserAttribute("stuff", stuffValue, session.getContext().getRealm())
                                .stream()  
                                .map(userModel -> ModelToRepresentation.toRepresentation(session, session.getContext().getRealm(), userModel))
                                .collect(toList());
    } 

    @Override
    public void close() {

    }
}

You'll find more details here : https://www.keycloak.org/docs/latest/server_development/index.html#_extensions_rest

Lucas Declercq
  • 1,534
  • 11
  • 17
  • Thank you. This basically works. For me there was the problem though, that Jackson needed to access fields, after the transaction was committed. In my case, I was only interested in the ids, so I could just extract them and return plain Strings instead. In the Keycloak examples, they return DTOs instead of Entities (CompanyRepresentation instead of Company for example). See [here](https://github.com/keycloak/keycloak/blob/a77c35ea8fc2157439c3d5d5787de760dc0cbb14/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/spi/impl/ExampleServiceImpl.java#L59) – Lyannic Apr 29 '20 at 15:51
  • 1
    Yes sorry, you must return representations not models, so you need to map the users using ModelToRepresentation.toRepresentation(). I updated my response. – Lucas Declercq Apr 30 '20 at 17:03
  • Thanks for this wonderful answer! I was wondering whether it is possible to search within a group? It looks straight forward to do this after fetching the users with a search, but I'm afraid that would be to memory/cpu intensive. – Thomas Stubbe Sep 25 '20 at 14:25
  • You could retrieve the Entity Manager session.getProvider(JpaConnectionProvider.class).getEntityManager(); and build a custom query to filter users by groups/roles – Lucas Declercq Jan 15 '21 at 13:00
  • Time passes and APIs change: stackoverflow.com/a/71838958/717732 ; since your answer is at the moment quite high-ranked, please add a note about which VERSION of Keycloak you wrote the answer for. Depending on the version, it may be an overkill for simple cases. Still, knowing that you can add/customize the lookup is a very important bit in tough cases, thanks! – quetzalcoatl May 09 '22 at 15:20
5

With latest version of keycloak (18.01), we have api in


    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    List<UserRepresentation> searchByAttributes(@QueryParam("q") String searchQuery);

The query param is of format 'key:value' . Using this we can get list of all users by custom attributes

Anil Bhat
  • 51
  • 1
  • 2
3

Update: The /auth path was removed starting with Keycloak 17 Quarkus distribution. So you might need to remove the /auth from the endpoint calls presented on this answer.


Keycloak versions from 15.1.0 upwards

Although not mentioned on the release notes it is possible after Keycloak version 15.1.0 (as pointed out by @Darko) to search users by custom attributes, introduced with this commit. As one can now see on the GET /{realm}/users endpoint of the Keycloak Admin Rest API:

enter image description here

Form example:

curl 'https://${KEYCLOAL_HOST}/auth/admin/realms/${REALM_NAME}/users?q=employeeNumber:444555'

Keycloak versions before 15.1.0

For version before 15.1.0, out-of-the-box you can use the Keycloak Admin API endpoint:

GET /{realm}/users

one can read that :

Get users Returns a list of users, filtered according to query parameters

those (optional) query parameters being:

  • briefRepresentation (boolean);
  • email (string);
  • first (string);
  • firstName (string);
  • lastName (string);
  • max (Maximum results size (defaults to 100)) (integer);
  • search (A String contained in username, first or last name, or email);
  • username (string).

As you can see you cannot search for custom attributes. A not so great solution is to get all the users (max=-1), and filter afterwards by the custom attribute.

The other option (pointed out by @Lucas) is to extend Keycloak functionality by adding your own custom Service Provider Interfaces (SPI) and adding your custom endpoint. There you can take advantage of the searchForUserByUserAttribute method from the UserQueryProvider interface.

Step-by-step with Keycloak Admin API versions from 15.1.0 upwards

To use the Keycloak Admin REST API, you need an access token from a user with the proper permissions. For now, I will be using the admin user from the master realm, and later explain how to use another user:

curl “https://${KEYCLOAK_HOST}/auth/realms/master/protocol/openid-connect/token” \
    -d "client_id=admin-cli" \
    -d "username=${ADMIN_NAME}” \
    -d "password=${ADMIN_PASSWORD}" \
    -d "grant_type=password"

You get a JSON response with the admin's token. Extract the value of property access_token from that response. Let us save it in the variable $ACCESS_TOKEN for later reference.

To get the list of users from your realm $REALM_NAME with a given set of attributes (i.e., ${ATTRIBUTES}).

curl -X GET “https://${KEYCLOAK_HOST}/auth/admin/realms/${REALM_NAME}/users?q=${ATTRIBUTES}” \
     -H "Content-Type: application/json" \
     -H "Authorization: bearer ${ACCESS_TOKEN}”

I have the aforementioned steps coded in the script getUserByAttributes.sh on my GitHub repo for those that are interested. An example :

sh getUserByAttributes.sh localhost:8080 admin admin test_realm 'employeeNumber:4445 something:a'

Assigning the proper user permissions

For those that do not want to get an access token from the master admin user, you can get it from another user but that user needs the permission manage-users from the realm-management client. For that you can check this answer on how to do it

dreamcrash
  • 47,137
  • 25
  • 94
  • 117
1

Current Keycloak API version is 4.8 and there is API: Get users Returns a list of users, filtered according to query parameters

GET /{realm}/users

See doc: https://www.keycloak.org/docs-api/4.8/rest-api/index.html#_users_resource

Only this "search" is available from the API. If you need search by user attributes, then you need to implement it in your own code.

Jan Garaj
  • 25,598
  • 3
  • 38
  • 59
0

You can filter keycloak users using their custom attributes by passing the 'q' get parameter:

IN SUMMARY:

<get-users-url>?q=key1:value1 key2:value2

EXAMPLE:

   curl --location --request GET 'http://localhost:8080/admin/realms/realm-name/users?q=key1:value1 key2:value2' \
        --header 'Authorization: Bearer <your-token>'