Code With Ben Knox

Fix: Keycloak Users API 403 Error

Backend

December 8th, 2025

It is common to store app users in an identity provider (IdP). My IdP of choice is Keycloak, because it is easy to deploy in any Kubernetes cluster. After scaffolding, my experience is often: pull in code requesting the users API, create a user, see API return 403 Forbidden, and pull my hair out. Here is how to fix it.

Prerequisites

- You need a Keycloak instance where you can access the REST API, I wrote an article on how to deploy Keycloak on Kubernetes here

- curl for sending example requests

Opening Note

First some, context before I explain how to fix the 403 Forbidden error mentioned above. The definition of a 403 Forbidden error "indicates that the server understood the request but refused to process it" (Mozilla's documentation). And this tells us a lot about the problem, it means we are authenticated, i.e. we have the right credentials. If we weren't authenticated the response would be 401 Unauthorized, which "is similar to the 403 Forbidden response, except that a 403 is returned when a request contains valid credentials, but the client does not have permissions to perform a certain action" (Mozilla's documentation). Essentially Keycloak is saying "You're not allowed!"

The Problem

In my case the problem occurs during or after I've built my signup and login flow for a new app, usually when you need to access sensitive user data. One of the routes involved is [GET] /admin/realms/{realm}/users/{user-id}, which is an admin-level route. I'll focus on that route because it requires permissions and results in the aforementioned 403 if not set up correctly, it's a good example but there are of course other routes you will have this problem with.


In addition, here is an example of some problem code I've passed around that calls the users API to get user details by their id in TypeScript:

The Solution

Because the route above is an admin route we actually need to use credentials that have the correct permissions from the realm the user belongs to, for getting a user by the id, we need "view-users" role specifically, here is a list of all available roles.

Step 1 - Configure A Realm and Client

Before we can actually solve the problem, we need to create the problem. Follow the steps below to create a client that we can use to see the 403 Forbidden error:

1. Log in to our Keycloak instance

2. Create a realm for your app, I will name mine 403-forbidden-fix. Keep enabled checked

3. In the navigation under our realm click Clients, and click the Create Client button

4. Give our client a name and click next, I will name mine 403-forbidden-fix-client

5. In the next form turn on Client authentication (leave authorization off) and make sure Standard flow and Direct access grants are checked

6. In that same form make sure to check Service account roles too, click next

7. If you want to also add a few valid redirect URIs for your app, these are URIs that Kubernetes will use as callbacks from the OIDC flow so for this example it doesn't matter much

8. Then click save


We will need the client id above "403-forbidden-fix-client" and in the client details we should be able to find the client secret. Here is how: click on the credentials tab and make note of our secret value, we will need it for curl requests when we try the users API.

Step 2 - Create a User

Let's create a user, so we can try to get the details using the admin API:

1. Log in to our Keycloak instance

2. Select the 403-forbidden-fix realm we just created

3. Click on the Users link in the navigation on the left

4. Click the "Create new user" button

5. Give the user a username and email, I will give him the username "john-doe" and "john-doe@example.com"


Make note of the ID field after we create the user, we will use it in the curl requests we make when we try the users API.

Step 3 - Users By ID Attempt 1

So now that we have all of that taken care of, let's try running the [GET] /admin/realms/{realm}/users/{user-id} with curl. The script below uses the oidc layers implemented by Keycloak to get a token and uses that token with the Authorization Bearer scheme in our problem uri (users by id):

What we should see is the problem we need to fix, a 403 Forbidden. In the next step we'll do the work to resolve the issue.

Step 4 - Assign the View Users Role

In Step 1 we created our "403-forbidden-fix-client" client with the "Service accounts roles" enabled, this is where we need to add the Keycloak role "view-users" so [GET] /admin/realms/{realm}/users/{user-id} is allowed by the server. Here are the steps to assign the correct role:

1. Log in to our Keycloak instance

2. Select the 403-forbidden-fix-client we created in Step 1

3. Click on the Service accounts roles tab

4. Click the Assign role drop down

5. Click Client roles

6. Search for view-users and check it

7. Click the Assign button

Step 5 - Users By ID Attempt 2

And that's it! You should now be able to get the user details by the ID, try the curl script again:

You can do this for any of the roles required for Keycloak APIs that you will need to access in your backend, but keep in mind least privilege access principle 😉.

Conclusion

This post highlighted a frequent pain point I have run into while setting up a new app with Keycloak enabled identity management. We talked about 403 vs 401 a bit, created a client that is not properly scoped to allow requests to [GET] /admin/realms/{realm}/users/{user-id}, and then we fixed the issue by assigning the view-users role to the client. Happy coding! 🧑‍💻