sisisisi
sisisisi

Reputation: 621

How does keycloak determine which signature algorithm to use?

I'm writing an application that uses keycloak as its user authentication service. I have normal users, who log in to keycloak from the frontend (web browsers), and service users, who log in from the backend (PHP on IIS). However, when I log in from the backend, keycloak uses HS256 as its signature algorithm for the access token, and thus rejects it for further communication because RS256 is set in the realm and client settings. To get around this issue, I would like to "pretend to be the frontend" to get RS256 signed access tokens for my service users.

For security reasons, I cannot give the HS256 key to the application server, as it's symmetrical and too many people can access the server's code.

I am currently debugging the issue using the same user/pw/client id/grant type both on the frontend and the backend, so that cannot be the issue.

So far I have tried these with no luck:

So how does keycloak determine which algorithm to sign tokens with? If it's different from version to version, where should I look in keycloak's code for the answer?

EDIT: clarification of the flow of login and reasons why backend handles it.

If a user logs in, this is what happens:

  1. client --[login data]--> keycloak server
  2. keycloak server --[access and refresh token with direct token granting]--> client
  3. client --[access token]--> app server
  4. (app server validates access token)
  5. app server --[data]--> client

But in some occasions the fifth step's data is the list of users that exist in my realm. The problem with this is that keycloak requires one to have the view-users role to list users, which only exists in the master realm, so I cannot use the logged in user's token to retrieve it.
For this case, I created a special service user in the master realm that has the view-users role, and gets the data like this:

  1. client --[asks for list of users]--> app server
  2. app server --[login data of service user]--> keycloak server
  3. keycloak server --[access token with direct granting]-->app server
  4. app server --[access token]--> keycloak server's get user list API endpoint
  5. (app server filters detailed user data to just a list of usernames)
  6. app server --[list of users]--> client

This makes the the list of usernames effectively public, but all other data remains hidden from the clients - and for security/privacy reasons, I want to keep it this way, so I can't just put the service user's login data in a JS variable on the frontend.

In the latter list, step 4 is the one that fails, as step 3 returns a HS256 signed access token. In the former list, step 2 correctly returns an RS256 signed access token.

Upvotes: 5

Views: 6722

Answers (1)

bsaverino
bsaverino

Reputation: 1285

Thank you for the clarification. If I may, I will answer your question maybe differently than expected. While you focus on the token signature algorithm, I think there are either mistakes within your OAuth2 flows regarding their usage, or you are facing some misunderstanding.

The fact that both the backend and frontend use "Direct Access Granting" which refers to the OAuth2 flow Resources Owner Credentials Grant is either a false claim or is a mistake in your architecture.

As stated by Keycloak's own documentation (but also slightly differently in official OAuth.2 references):

Resource Owner Password Credentials Grant (Direct Access Grants) ... is used by REST clients that want to obtain a token on behalf of a user. It is one HTTP POST request that contains the credentials of the user as well as the id of the client and the client’s secret (if it is a confidential client). The user’s credentials are sent within form parameters. The HTTP response contains identity, access, and refresh tokens.

As far as I can see the application(s) and use case(s) you've described do NOT need this flow.

My proposal

Instead what I'd have seen in your case for flow (1) is Authorization Code flow ...

  • assuming that "Client" refers to normal users in Browser (redirected to Keycloak auth. from your front app)
  • and assuming you do not actually need the id and access tokens back in your client, unless you have a valid reasonable reason. As the flows allowing that are considered legacy/deprecated and no more recommended. In this case, we would be speaking of Implicit Flow (and Password Grant flow is also discouraged now).

So I think that the presented exchange (first sequence with points 1 to 5 in your post) is invalid at some point.


For the second flow (backend -> list users), I'd propose two modifications:

  • Allow users to poll the front end application for the list of users and in turn the front-end will ask the backend to return it. The backend having a service account to a client with view-roles will be able to get the required data:

     Client (logged) --> Request list.users to FRONTEND app --> Get list.users from BACKEND app
                                                                   (<--> Keycloak Server)
                     <----------------------------------------- Return data.
    
  • Use Client Credentials Grant (flow) for Backend <> Keycloak exchanges for this use case. The app will have a service account to which you can assign specific scopes+roles. It will not work on-behalf of any user (even though you could retrieve the original requester another way!) but will do its work in a perfectly safe manner and kept simple. You can even define a specific Client for these exchanges that would be bearer-only.


After all if you go that way you don't have to worry about tokens signature or anything like that. This is handled automatically according to the scheme, flow and parties involved. I believe that by incorrectly making use of the flows you end up having to deal with tricky token issues. According to me that is the root cause and it will be more helpful than focusing on the signature problem. What do you think?

Did I miss something or am I completely wrong...? You tell me.

Upvotes: 0

Related Questions