Keycloak Custom Rest Api (Search by user attribute - Keycloak)
Tags: keycloak, customapi, api
Published: 2021-04-18 16:01:04

In this project we are going to develop and integrate a custom rest api in keycloak server.

## About Keycloak
Keycloak is an open source Identity and Access Management solution aimed at modern applications and services. It makes it easy to secure applications and services with little to no code. It provides with following features,
- Single-Sign On
- Identity Brokering and Social Login
- User Federation
- Client Adapters
- Admin Console
- Account Management Console
- **Standard Protocols**: OpenID Connect, OAuth 2.0, and SAML.

## Keycloak setup
We are going to use docker container to run Keycloak along with postgreSQL. We have integrated PostgreSQL with Keycloak inside `docker-compose.yml` file. 
{% gist https://gist.github.com/silentrobi/1fdfcbe9290ff2f6a148c5e0f5440019 %}
To setup the docker containers, run  the following command.
```
docker-compose -f ./docker-compose.yml up -d
``` 
Now, your keycloak should run locally on `8090` port.
## Keycloak setup and adding user
URL for keycloak `http://localhost:8090/`

{% youtube fPqUrezIT6M %}

>**Note**: By default keycloak uses `Master` realm. As you can see we added user in `Demo` realm. In order to create new realm, do as follow
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0jb8t1leg0a0dy0vnux2.png)
 
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z5iqlddpbwsqh1u7bilj.png)
Now lets create a **maven** project. I will use VS Code as IDE for this project.However, you can use any IDE of your choice. You can check this [link](https://code.visualstudio.com/docs/java/java-project) to configure VS Code for Java development.
## Project Structure 
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dgdw516f0rctkj73qvig.png) 

**pom.xml** file contains all the required dependencies. You can copy the dependencies in your project.
{% gist https://gist.github.com/silentrobi/1b1ccab480dfb58cebf2da1174c69672 
%}
Create a model user class `UserDto.java` under models folder.
{% gist
https://gist.github.com/silentrobi/fbbee3db4f5bbcde4bf9e54d27be92aa %}

Create a mapper class that will map keycloak's **UserModel** class object to **UserDto** class object. Use `import org.keycloak.models.UserModel;` to import **UserModel** class.

{% gist 
https://gist.github.com/silentrobi/31cade953b6d48280eda19c0a1edbbb6 %}
Keycloak provides ***RealmResourceProvider*** and ***RealmResourceProviderFactory*** interfaces that are used to implement custom rest api. 
First we create ***KeyCloakUserApiProvider*** class that implements ***RealmResourceProvider*** interface. We will then define our custome api method named `searchUsersByAttribute`.
```java
    @GET
    @Path("users/search-by-attr")
    @NoCache
    @Produces({ MediaType.APPLICATION_JSON })
    @Encoded
    public List<UserDto> searchUsersByAttribute(@DefaultValue(defaultAttr) @QueryParam("attr") String attr,
            @QueryParam("value") String value) {
        return session.users().searchForUserByUserAttribute(attr, value, session.getContext().getRealm())
                .stream().map(e -> userMapper.mapToUserDto(e)).collect(Collectors.toList());
    }
``` 
The above method filters user list based on user attribute. Default filter attribute is `merchant_id`.
## KeyCloakUserApiProvider class
Use `import org.keycloak.services.resource.RealmResourceProvider;` to import the interface.
{% gist 
https://gist.github.com/silentrobi/5656161960429b5060b5e4642e0bd6cf %}
Lets define ***KeyCloakUserApiProviderFactory*** class that implements ***RealmResourceProviderFactory***.

## KeyCloakUserApiProviderFactory class
{% gist
https://gist.github.com/silentrobi/f5abf27f234ff78c17f62e6905b66ace %}

> **Note:** Factory instance will remain through out the lifecycle of keycloak server but ***KeyCloakUserApiProvider*** instance will be created at run time.

Register the ***KeyCloakUserApiProviderFactory*** class to keycloak by creating `org.keycloak.services.resource.RealmResourceProviderFactory` file under `src\main\resources\META-INF\services\`  folder. 
Next copy the ***KeyCloakUserApiProviderFactory*** class name including package information into that file. For an example,

{% gist
https://gist.github.com/silentrobi/66b94b96aa54c4fc554977d09a5ec683
%}
After that, build the maven project by running `mvn clean install`. This will generate a `target` folder. Under the target folder there will be `{project artifact id}-*.jar` file. 

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/awwt8brvq5s0hzraj7xk.png)

Copy that jar file to the Keycloak's `standalone/deployments/` directory. For an example, If you run your Keycloak in docker container, you can use the following command:
```
docker cp <jar_file_path> keycloak:/opt/jboss/keycloak/standalone/deployments/
```
## Test our custom api

Get list of users with `merchant_id 1`
```shell
curl --location --request GET 'http://localhost:8090/auth/realms/demo/userapi-rest/users/search-by-attr?attr=merchant_id&value=1'
```
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s9btmfzdnf7axmrvf1qa.png)
 
You can find the project on this GitHub [repository](https://github.com/silentrobi/keycloak-custom-api-searchby-attr).

If you find this article useful, kindly give a start on GitHub.