Get a public client to communicate with a confidential client

I am creating a web app where a user logs in via Keycloak and can use the UI. The UI has a public client and generates a JWT token when any requests are sent to the backend. The backend has a confidential client (on the same realm as the public client) but when API requests are sent from the UI to the backend I get a 401 Unauthorized response.
How can I have a secure backend with a public frontend and allow both to communicate with one anohter?

Anyone able to help me on this…???

Why does the backen give 401? What is the backend expecting in the JWT? Does it check for a specific claim value?

Why does the backen give 401?

I can only assume it gives a 401 because the frontend is public and the backend is confidential. But could be completely wrong with that.

What is the backend expecting in the JWT? Does it check for a specific claim value?

I don’t know the specifics of the JWT. I didn’t define it or what should go in the token.

I just thought with both clients being on the same realm, they would be able to communicate with one another. The backend is confidential as I am making api requests to add more users via api calls and I want to make sure only my code can do it and can only make certain calls at that!

The frontend is public because it is accessable via the UI (browser) but I want the frontend to be able to make API calls to the backend.

So my question is can a public client communicate with a backend client on the same realm?

That has nothing to do with public or confidential. 401 means that the frontend is sending no token or is sending a token with missing contents, wrong signature, expired lifetime, wrong audience, wrong scope… That’s why I asked “Why does the backend give 401”. Do you have any logs?

Yes. The public frontend client has to put the claims and values in the token the backend expects/checks. Just beeing on the same realm is not enough. Realms are the multi-tenency concept of keycloak, they are practically not reflected in the tokens.

I have keycloak running on docker compose and have the logging set to debug but crawling through it, nothing is showing, nothing of use anyway. The backend is ran on a quarkus app and I have it set that the user needs to be authenticated to gain access to the backend. The user logs in via the frontend (UI) but this is technically to the frontend client.

So thinking on this, is there a way to be able to login via the frontend and then use the one token (generated by the frontend) to access the backend? This is a complete new area to me and one I have very little experience on, hence the trivial questions

You won’t find anything in keycloak’s log because from keycloak’s view everything is ok. Do you have logs of your quarkus backend? You have to find out why the backend does not accept the token. Typically in a bearer auth secured backend, you have to configure what issuer and what audience the token has to have.

Shot in the blue: Add an audience mapper to the frontend’s client configuration in keycloak and set the value to the client id of the backend, then include the mapper to access tokens. Configure your backend to acceppt the backend’s client id and to verify the token against keycloak’s realm issuer (https://your-keycloak.domain/auth/realm/yourrealm)

There is no logs on quarkus either, but I will try run it with debug logging.
The backend requires the user to be logged in, but that’s to the backend client. The user is logged in but it’s to the frontend client.
Is there a way I can construct the JWT on keycloak to accept tokens from the frontend client to the backend client?

In the frontend’s client configuration in keycloak you can define mappers. With mappers, you can control what keycloak puts in the JWTs. Some standard mappers are bound to scopes and are enabled by default. But in the mappers section of a client, you can customize almost any JWT claim and its value.

You were 100% right, it wasn’t a keycloak issue, it was oidc setup on quarkus! I had the keycloak address configured as localhost but they key was being compared against 127.0.0.1. Once I changed it to the IP, it worked! Thanks for your help