Skip to content

Conversation

@mabartos
Copy link
Contributor

@mabartos mabartos commented Nov 27, 2025


  • Added HTTP method annotation to impl classes for better visibility
  • Path changed admin/api/v2/realms/master/clients/* --> admin/master/api/clients/v2/clients/*
  • No need for the RealmApis
  • Created the ClientsApiGroup
  • When no version is specified, the default is used -> admin/master/api/clients/ = admin/master/api/clients/v2
  • Then, there might be some other client-related resource like admin/master/api/clients/v2/scopes,...

@shawkins
Copy link
Contributor

When the version is not present, the default is used -> /clients -> /clients/v2

Is this for the dev experience? We shouldn't provide a endpoint with a schema that may change. Alternatively with additional metadata facilties you could perhaps advertise the default api version.

Or do you wanna be more explicit, and the version needs to be specified in the path always?

Everything should be versioned for consistency. Here again metadata facilities could be needed to advertise the versions.

This will start to resemble the way kubernetes versions apis - /group/version/[namespace/name]/resource

Do we want to consider a group concept, or is the thinking that every root resource is separately versioned - even if there are relationships between them?

@mabartos
Copy link
Contributor Author

mabartos commented Dec 1, 2025

Is this for the dev experience? We shouldn't provide a endpoint with a schema that may change. Alternatively with additional metadata facilties you could perhaps advertise the default api version.

Yes, the intention is mostly for dev experience - having the same convention as for features. It means, that we recommended to our users to use the versioned keys for features, but we accept also the unversioned feature name to be enabled.

However, as we start this whole new thing, we can do some changes right away. It means that we can decide to be always on the consistent right way - requiring the version to be always specified.

To be fully consistent, as mentioned, we should have the API path for clients as follows:

/admin/api/realms/<realm-api-version>/<realm-name>/clients/<client-api-version>/*

So f.e:

/admin/api/realms/v1/master/clients/v2/

I'm ok to have it like this as it's an API and the dev experience does not have to be so "strict" as we have the OpenAPI and swagger anyway.

@vmuzikar @keycloak/cloud-native-maintainers WDYT?


Alternatively with additional metadata facilties you could perhaps advertise the default api version.

Do you have any brief example/use-case how it could look like and how it could be used? Thanks


This will start to resemble the way kubernetes versions apis - /group/version/[namespace/name]/resource. Do we want to consider a group concept, or is the thinking that every root resource is separately versioned - even if there are relationships between them?

@shawkins Not sure how it'd look like. Do you have any Keycloak specific example how we could leverage groups?

@shawkins
Copy link
Contributor

shawkins commented Dec 1, 2025

Yes, the intention is mostly for dev experience - having the same convention as for features.

I think the belief for features is that most version changes won't have incompatiblity concerns.

I don't think the assumption holds here as for example the difference between v1 and v2 is that they are completely incompatible. It would be best not to offer this style of endpoint from the start.

To be fully consistent, as mentioned, we should have the API path for clients as follows:

This is part of the issue I meant about relationships between the entities. I'm not sure something like /admin/api/realms/v1/master/clients/v2/ makes sense.

Unless we now know the relationship structure for all api versions moving forward, then we probably don't want this kind of cross-version relationship. There could for example be invalid combinations moving forward that is a realm v3 might only support foo-clients, not clients. Then do we start the versioning of foo-clients at v1 or skip directly to v3?

I realize this is a contrived example, but hopefully it conveys the problem.

Do you have any brief example/use-case how it could look like and how it could be used? Thanks

For example https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#definitions - they have preferred group version defined. Clients could fetch the metadata, then know what default version is.

@shawkins Not sure how it'd look like. Do you have any Keycloak specific example how we could leverage groups?

If there are distinct subgraphs of resources under realms, they could be grouped.

@mabartos
Copy link
Contributor Author

mabartos commented Dec 2, 2025

It would be best not to offer this style of endpoint from the start.

@shawkins Thanks. +1

Unless we now know the relationship structure for all api versions moving forward, then we probably don't want this kind of cross-version relationship.

Agree.

If there are distinct subgraphs of resources under realms, they could be grouped.

Let's start simple, with not complicating things for Client API v2 for now, and solves the grouping of other potential APIs later - those would have a different path anyway, so there should not be any clash with that what we introduce now.

mabartos added a commit to mabartos/keycloak that referenced this pull request Dec 2, 2025
@mabartos mabartos requested a review from a team as a code owner December 2, 2025 13:47
@mabartos
Copy link
Contributor Author

mabartos commented Dec 2, 2025

@keycloak/cloud-native @shawkins Updated (also PR description).

@vmuzikar
Copy link
Contributor

vmuzikar commented Dec 2, 2025

I don't like mixing the schemes (i.e. /admin/api/realms/<realm-api-version>/<realm-name>/clients/<client-api-version>/*) either. What if we decoupled the realms from the version like this: /admin/api/clients/<client-api-version>/<realm-name>/*. I.e. having the realm represented only as a path param inside the Clients API.

@vmuzikar
Copy link
Contributor

vmuzikar commented Dec 2, 2025

CC @stianst

@mabartos
Copy link
Contributor Author

mabartos commented Dec 2, 2025

What if we decoupled the realms from the version like this: /admin/api/clients///*. I.e. having the realm represented only as a path param inside the Clients API.

@vmuzikar Thanks for the comment. I don't think it's a proper resource-based approach, as there should be a hierarchy of these resources (clients are part of the realm).


TL;DR I think the /admin/api/realms/<realm>/clients/v2 is ok (Realm API v2 is quite a far future IMHO).

Having only the /admin/api/clients/v2 path requires having the realm identified somehow. It means either via path/query param, or have it include it in the payload as "realm" attribute of the client rep. The path/query param does not really make sense to me as people would be confused on how to even use it. Having it in the payload is not so bad in this case, but I'd prefer to have the separation on the resource level (path level) for better isolation.

@vmuzikar
Copy link
Contributor

vmuzikar commented Dec 2, 2025

as there should be a hierarchy of these resources

I guess I was trying to say that this ^^ kinda contradicts the request for having distinct versions of the individual APIs. Either it's a single API with proper structure, or it's separate APIs with just references to cross-API resources

Realm API v2 is quite a far future IMHO

But what then? Are we ok with /admin/api/realms/v2/<realm>/clients/v2?

@vmuzikar
Copy link
Contributor

vmuzikar commented Dec 2, 2025

To summarize an offline discussion. We agreed on the following two alternatives:

  1. /admin/api/<api-group>/<api-version>/<realm-name>/*
    • E.g. GET /admin/api/clients/v2/my-realm/clients/my-client-id
  2. /admin/api/<api-group>/<api-version>/realms/<realm-name>/*
    • E.g. GET /admin/api/clients/v2/realms/my-realm/clients/my-client-id

Option 1 doesn't leave our door open if we ever needed global resources that are not tied to any realm, option 2 does. Another alternative would be to use a reserved word in place of a realm name should a resource be considered global. E.g. GET /admin/api/clients/v2/GLOBAL/clients/my-client-id would represent a hypothetical client that is not belonging to any realm.

I'd vote for option 1 as it doesn't imply the realm is a resource – having /realms/<realm-name> in a path suggests I can do e.g. GET /admin/api/clients/v2/realms/my-realm which is invalid for getting the realm resource as that's the Client API group (/admin/api/clients).

@stianst What are your thoughts? Should we even consider the possibility for global resources?

@shawkins
Copy link
Contributor

shawkins commented Dec 2, 2025

I'd vote for option 1 as it doesn't imply the realm is a resource – having /realms/ in a path suggests I can do e.g. GET /admin/api/clients/v2/realms/my-realm which is invalid for getting the realm resource as that's the Client API group (/admin/api/clients).

Realm is a built-in concept of containment. Here we are using exactly the same form of URL as Kubernetes - /group/version/namespaces/<namespace-name>/resource - and it's well understood that you aren't able to retreive the namespace via /group/version/namespaces/<namespace-name>, nor is it suggested you can in any of the api documentation or spec. Also most of the time users won't be hand-crafting the urls - it will be done via a client / tooling.

@mabartos
Copy link
Contributor Author

mabartos commented Dec 3, 2025

@shawkins btw. I added the code formatting for your examples, because the <> content was not visible.


After yesterday's discussion, I would opt for option 2 and basically follow the Kubernetes approach. Yesterday, I had concerns about the intuitiveness of the path for users, but as was mentioned, it's an API that will be used by the generated clients. We'll have a nice, polished OpenAPI spec, with nice endpoint visibility.

I'd say the namespace|realm should be clear from the first look and the /realms/ should be there the same as there's the /namespaces/ in k8s. Having the reserved word for the realm name is very error-prone. With the option 2, we can be prepared more for the future, and we do not risk any issue on our users/customers side when potentially they have the realm named like that (even this small risk is there).

@shawkins @vmuzikar So, I'm for Option 2 as there are more benefits than tradeoffs.

mabartos added a commit to mabartos/keycloak that referenced this pull request Dec 3, 2025
@mabartos
Copy link
Contributor Author

mabartos commented Dec 3, 2025

@vmuzikar @shawkins Updated based on the Option 2 now. Please review, and we can further discuss whether Option 1 or Option 2.

@stianst
Copy link
Contributor

stianst commented Dec 8, 2025

I see realm as the tenant, so should be the base of the URL, something like:

<my realm URL>/admin/clients/v2

This allows us to in the future to have things like virtual hosts that points to a realm; it also makes it easier to use different API groups for the same realm, as the base URL doesn't change.

Also, adding that in case you want to move a realm to a different cluster, today that can be done by changing the core protocols URLs (/realms/myrealm) and the core admin API ('/admin/api/myrealm`), but if you add the realm name into each API group, then that becomes more or less impossible to do.

@mabartos
Copy link
Contributor Author

mabartos commented Dec 8, 2025

@stianst Having the realm defined in the beginning looks good to me.

So by default, it might look like this:

localhost:8080/realms/test/admin/clients/v2

Is it what was intended, right?

@vmuzikar @shawkins WDYT?

mabartos added a commit to mabartos/keycloak that referenced this pull request Dec 15, 2025
mabartos added a commit to mabartos/keycloak that referenced this pull request Dec 15, 2025
@mabartos
Copy link
Contributor Author

mabartos commented Dec 15, 2025

Summary

  • Path changed admin/api/v2/realms/master/clients/* --> admin/master/api/clients/v2/clients/*
  • No need for the RealmApis
  • Created the ClientsApiGroup
  • When no version is specified, the default is used -> admin/master/api/clients/ = admin/master/api/clients/v2
  • Warned about not using the version for the API group in Javadoc
  • Added HTTP method annotation to impl classes for better visibility
  • Then, there might be some other client-related resource like admin/master/api/clients/v2/scopes,...

@vmuzikar @shawkins @stianst WDYT? We can continue with improvements in follow-up tasks.

@mabartos mabartos marked this pull request as ready for review December 15, 2025 11:43
@mabartos mabartos marked this pull request as draft December 15, 2025 12:54
@shawkins
Copy link
Contributor

shawkins commented Dec 15, 2025

Just wanted to add more from our v2 meeting. What I'm basically advocated for is along the lines of front-end url == virtural host, which is discussed in #14623 and related issues.

To support something like this we need an additional realm option to omit realms/name in paths we construct.

Just as today when you set a front-end url at a proxy level you'd still need the mapping:

front-end -> kc-host / realms / name

But instead of accessing keycloak via front-end / realms / name, users would use just front-end /

Admin access by default looks like:

front-end / admin -> kc-host / realms / name / admin

However URLs for server scoped resources - realms, server-info, etc. - don't make much sense. At worst every server scoped resource would need added to a rule in the form of - front-end / resource -> kc-host / admin / resource - and we'd have to ensure there could never be a conflict between global resource types and top level paths available from a public realm.

Users are likely to need an admin specific mapping anyway to restrict access. An alternative is to only have realms/name omitted for front-end urls, and require an additional admin mapping of:

front-end / admin -> kc-host / admin

Now you have:

front-end / admin / realms / name -> kc-host / admin / realms / name
front-end / admin / server-info -> kc-host / admin / server-info

@vmuzikar can the requirement to have node level specific routing of admin requests using urls like kc-host / realms / name / admin be elaborated on?

And it was brought up in the meeting we could support both conventions. That is regardless of how they look, just serve requests such as:

kc-host / realms / name / admin / server-info
kc-host / realms / name / admin / realms-api / v2 / realms / name
kc-host / realms / name / admin / realms-api / v2 / realms

I'm not entirely sure, but I think to do this would need some additional realm level configuration option to indicate what admin paths should be formed.

cc @keycloak/cloud-native @sschu

Also this doesn't have to be based just upon the front-end url - you can have realm specific admin urls as well.

@vmuzikar
Copy link
Contributor

@shawkins Virtual hosts for realm identification is definitely something we should look into in the future but I don't see it as something we need to figure out now, it's not really conflicting with our current work around designing the realm-based multi-tenancy. We will need to have a good story for putting the realm name in the path regardless – not everyone will use virtual hosts.


To summarize today's discussion on the WG sync, we need to consider the following:

  • Multi-tenancy support. For this, we want to have the realm name as sort of prefix/namespace, see the previous comment.
    • The main question is whether to place the realm name before or after /admin/. Placing it before has the pro is that all endpoints (admin, frontend) use a single prefix which helps with routing based on tenant/realm name. The con is more difficult filtering of admin endpoints as they don't start with /admin.
      • Before: /realms/my-realm/admin/api/clients/v2/....
      • After: /admin/realms/my-realm/api/clients/v2/....
  • Future theoretical Realms API. If the realm name is a prefix in the path (as specified in the previous point) this might get confusing very quickly.
    • Seems the only correct way is to make the Realms API a global resource. I.e. instead of having something like /realms/my-realm/admin/api/realms/v2/realms/my-realm, we'd have only /admin/api/realms/v2/realms/my-realm.
    • To avoid ambiguity, we'll need include in the path /realms/<realm-name> instead of just /<realm-name>.
      • An alternative to this would be some reserved word, something like global but major problem would be a migration path if someone already uses that realm name.
  • /api/ segment in the path. We might not need it. Instead, we'd suffix the API groups with -api. This would also differentiate the group names from the resources names.
    • E.g. instead of /realms/my-realm/admin/api/clients/v2/clients/my-client, we'd have /realms/my-realm/admin/clients-api/v2/clients/my-client.

Overall proposal

  • Realms: /admin/realms-api/v2/realms/my-realm.
  • Any other (realm scoped) resource: /realms/my-realm/admin/clients-api/v2/clients/my-client-id.
    • Alternatively: /admin/realms/my-realm/clients-api/v2/clients/my-client-id

@shawkins
Copy link
Contributor

@shawkins Virtual hosts for realm identification is definitely something we should look into in the future

To clarify I'm referening virutal hosts because that's what @stianst was referencing above. However I'm trying, and probably failing, to relate this functionality to our realm-based front-end URL support and how I think users would actually want their full front-end urls to look. Let me see if I can make this less confusing.

but I don't see it as something we need to figure out now, it's not really conflicting with our current work around designing the realm-based multi-tenancy.

I see a strong overlap between the multi-tennancy concerns that are being brought up here and what URLs will be used externally and how that maps to internal URLs.

Let's say I have realm-a on cluster 1 and realm-x on cluster 2. Now I'm tasked with moving realm-a from cluster 1 to cluster 2.

Will realm-a and realm-x use the same hostname? Most likely not - which means this transition will involve setting a front-end url on realm-x. Or am I missing something here - are we considering using hostname-strict=false on cluster 2?

With the realm level front-end url set, I completely agree it is straight-forward to change how the proxy handles front-end / realms / realm-a from cluster-1-host / realms / realm-a to cluster-2-host / realms / realm-a.

A concern expressed above is that it will be difficult to handle admin access unless we have URLs with relative paths such as / realms / name / admin.

Again unless I'm missing something this is not generally possible today because we lack a per-realm ability to set the admin hostname url.

So let's assume that feature, or at least a feature that treats the realm front-end url as the admin url, has been added. If you are already handling front-end / realms / realm-a, I agree that also handles admin requests of this form as well. It was also mentioned that node specific routing may be needed for admin requests - or did I misunderstand something?

However using / realms / name / admin makes server scoped resource URLs messier (realms, server-info), and more makes it more complicated to generally restrict admin access.

Is that a fair assessment?

We will need to have a good story for putting the realm name in the path regardless – not everyone will use virtual hosts.

I'm not suggesting that they will - realm specific front-end URL differentiation could be based upon path, not just hostname.

@stianst
Copy link
Contributor

stianst commented Dec 16, 2025

Makes it simpler to switch version as you only need to make the changes not change the path.

In case we needed to bump the API version, it means we needed to do some radical braking changes. Changing the version in the path then will be the least of your concerns.

We? Or the user of the API? That all depends on what they are using or not. I could for instance just be doing a CURL and the endpoints I'm using hasn't changed.

@stianst
Copy link
Contributor

stianst commented Dec 16, 2025

We don't need to figure out the full virtual hosts story as part of this; there's a number of complications around that. Some may want a single virtual host that points to both the frontend and the admin endpoints. Some may want to expose it on different virtual hosts, or only use a virtual host for the frontend URLs, but not have a virtual host for the admin endpoints. Quite a lot needs changing to support this, and figuring out, hence why we haven't done that yet. My main point here was that the realm name must be before the API group, not after. Having it after made no sense anyways.

My suggestion for new endpoints are:

/admin/<realm name>/api/<api group>/<version>

Examples:

GET /admin/myrealm/api/clients/v2 - returns list of clients
POST /admin/myrealm/api/clients/v2 - creates a client
GET /admin/myrealm/api/clients/v2/myclient - returns the client with clientId=myclient

GET /admin/myrealm/api/realm/v2 - returns the realm config
PATCH /admin/myrealm/api/realm/v2 - partial update of the realm config
POST /admin/myrealm/api/realm/v2 - complete update of the realm config

GET /admin/master/api/realms/v2 - list all realms (only available on master realm)
POST /admin/master/api/realms/v2 - create a new realm
DELETE /admin/master/api/realms/myrealm/v2 - delete a realm

In all example URLs the version can be omitted, in which case the default version is used. I still would suggest using a header for version instead of path though.

@mabartos
Copy link
Contributor Author

EDIT: I see that @stianst is suggesting something similar as described below.

The main question is whether to place the realm name before or after /admin/. Placing it before has the pro is that all endpoints (admin, frontend) use a single prefix which helps with routing based on tenant/realm name. The con is more difficult filtering of admin endpoints as they don't start with /admin.

The situation around this is little bit different than using a single prefix.

Current Keycloak endpoints

We have Admin and non-Admin endpoints, like AdminRealmsResource and RealmsResource.

1. Realms resource - /realms/{realm}/*

For protocol handling(like OIDC), brokering, login actions,... Ops that are executed by non-admin users.

2. Admin Realms resource - /admin/realms/{realm}/*

We have this path for Admin realm resources (no server scoped resources).
It means that users/customers might have filtered the Admin API endpoints based on the prefix /admin/*.
When there's the /realms/{realm}/admin, the filtering will indeed be worse, as they would need to filter also the additional endpoints.

Summary

If we're able to reuse the /admin root without ambiguity, why not do it? As we should distinguish between the admin and non-admin endpoints anyway, on the proxy level, there should not be a big difference in how we map the front-end / realms / realm-a and the front-end / admin / realms / realm-a, right?

Maybe I'm missing something, but I don't see a reason why we can't use this suggestion (with RESTEasy, no ambiguity should be present due to the literal segments preference,..):

  • /admin/realms-api/v2/realms/my-realm - Realms API group (server scoped)
  • /admin/{realm}/clients-api/v2/ - Clients API group (realm-scoped)

As for the multi-tenancy and proxy-level mapping, users/customers have to already deal with the current /admin endpoints anyway, right? @shawkins I probably don't understand all your points, but can you elaborate on why the suggestion above might be problematic?

@vmuzikar
Copy link
Contributor

@shawkins I'm not sure I entirely understand the concerns. Could you please elaborate a bit more?

Now I'm tasked with moving realm-a from cluster 1 to cluster 2.

Could you elaborate what you mean here? It's be a single Keycloak instance, we wouldn't be moving realms. Do you mean swapping hostnames between two realms?

Again unless I'm missing something this is not generally possible today because we lack a per-realm ability to set the admin hostname url.

Yes, we do not support per realm admin URLs. That's something we'd need to tackle especially with virtual hosts but it's not something we need to find a solution for now, IMHO.

It was also mentioned that node specific routing may be needed for admin requests - or did I misunderstand something?

Yes, that's my understanding too. In multi-tenancy scenarios, some customers might be more heavy on the admin API and might have e.g. dedicated nodes.

However using / realms / name / admin makes server scoped resource URLs messier (realms, server-info), and more makes it more complicated to generally restrict admin access.

Is that a fair assessment?

I think yes.


@stianst

We? Or the user of the API?

The API user.

GET /admin/myrealm/api/clients/v2 - returns list of clients
POST /admin/myrealm/api/clients/v2 - creates a client

I don't really like having the root resource of the API the client list. What if I want to manage client scopes under the client API? IMHO the root resource should be "nothing", i.e. to get clients, you'd do GET /admin/myrealm/api/clients/v2/clients, for client scopes you'd do GET /admin/myrealm/api/clients/v2/scopes, etc.

GET /admin/myrealm/api/realm/v2 - returns the realm config

GET /admin/master/api/realms/v2 - list all realms (only available on master realm)

This IMHO feels quite confusing. Realms API vs Realm API. Realms accessible only via master realm. It's not really consistent.

Do you have any concerns with server scoped resources (that do not belong to any realm)?


@mabartos If I understand your proposal correctly, you suggest to have /admin before the realm identifier, right? I think I tend to agree with you that it has more advantages.

@mabartos
Copy link
Contributor Author

@mabartos If I understand your proposal correctly, you suggest to have /admin before the realm identifier, right? I think I tend to agree with you that it has more advantages.

@vmuzikar Yes. It'd also be consistent with our current Admin endpoints.

@shawkins
Copy link
Contributor

shawkins commented Dec 16, 2025

Could you elaborate what you mean here? It's be a single Keycloak instance, we wouldn't be moving realms. Do you mean swapping hostnames between two realms?

At one point I believe a justification for having all urls rooted by / realms / name was about how easy it would be to manipluate at the proxy level - including the ability to have a realm on one keycloak cluster migrated to another keycloak cluster. I was trying to expand upon that consideration, but perhaps my interpretation was not what was intended.

Yes, that's my understanding too. In multi-tenancy scenarios, some customers might be more heavy on the admin API and might have e.g. dedicated nodes.

This is something I'd like to better understand. Is this done currently? And what is the basis for the dedication - are for example the cluser nodes somehow hetrogeneous? Or is this seen as an extension of session affinity?

/admin/{realm}/clients-api/v2/ - Clients API group (realm-scoped)

@mabartos this is missing the realms term in the path, it should be - /admin/realms/{realm}/clients-api/v2/ - Clients API group (realm-scoped)

@shawkins I probably don't understand all your points, but can you elaborate on why the suggestion above might be problematic?

@stianst 's point from #44527 (comment) that he wants the realm name before the api group. That mostly works, but is conceptually confusing for realms themselves and other server scoped admin resources, which @vmuzikar notes in #44527 (comment)

It might help to walk through more examples and to clearly separate the thinking about external and internal urls.

Let's say we know that my-realm lives on kc-host. If the realm name is not in some simple location at the root of every external URL path, then we can only do proxy based logic if there is a 1-1 mapping between the admin-url and kc-host. Otherwise:

External Request Internal Request / Notes
front-end/realms/my-realm kc-host/realms/my-realm - Nothing new here, straight-forward to handle and works as expected
admin-url/admin/realms/my-realm/clients-api/v2/clients kc-host/admin/realms/my-realm/clients-api/v2/clients - Similarly straight-forward, but does require separate handling that then front-end
admin-url/admin/realms-api/v2/realms/my-realm I can determine the realm / host, but it's not straight-forward
admin-url/admin/server-info I don't know what host this should go to because there is no realm

When would the admin-url not be 1-1 with the kc-host? Unless I'm missing something, this only comes into play when there are multiple keycloak clusters behind a single proxy - which relates to the case mentioned before about moving a realm from being hosted on one keycloak cluster to another.

The less exotic scenario here is wanting the proxy to do realm specific access restrictions.

Finally yet another scenario that was broached involves per realm mappings to specific cluster nodes - I don't have a good grasp on when and why this is being done yet, but that could also influence what seems like an acceptable solution.

We can make the per realm manipulation straight-forward if instead we do:

External Request Internal Request / Notes
admin-url/admin/realms/my-realm/realms-api/v2/realms/my-realm kc-host/admin/realms/my-realm/realms-api/v2/realms/my-realm - I can easly determine the realm, but both internal and extenral URLs are ugly
admin-url/admin/realms/my-realm/server-info kc-host/admin/realms/my-realm/server-info - "

Where do we go from here:

  1. Use @stianst 's suggestion to create additional special case handling for realm URLs in particular
  2. Just accept the ugliness and move on for now.
  3. I believe we have ways to improve upon these URLs, but only if we are willing to expand on constructs like the realm specific front-end url. I understand that is even more new functionality and may only be confusing things more at this point, so bringing this up is just to further tha case that we could accept the ugliness and move on, then revisit this later.

@mabartos
Copy link
Contributor Author

@shawkins Thanks for the clarification.

I've just updated the PR a little to include the /realms segment.

However, I had to add also the /api segment to distinguish between the current Admin API and the new one to prevent any ambiguity.

So, the path looks like this: /admin/realms/{realm-ame}/api/<api-group>/ now.

@shawkins @vmuzikar Unfortunately, I can't allocate more time to this before Christmas, so feel free to update this PR (or create a new one) based on your discussion.

Thanks!

@mabartos mabartos marked this pull request as ready for review December 17, 2025 13:14
@stianst
Copy link
Contributor

stianst commented Dec 17, 2025

I'm a little bit lost in this conversation by now, and not really clear on what everyone is suggestion.

What's wrong with what I've been suggesting from the start /admin/myrealm/api/clients/v2?

  • /realms/ is just unnecessary and provides no value to have it there
  • GET ../clients/v2/clients to list clients is just weird, and scopes will be on it's own API, not under client API. That's literally the whole point of API groups
  • /clients-api is weird, it should be /api/clients/

@sschu
Copy link
Contributor

sschu commented Dec 17, 2025

The assumption was that an api group subsumes different types of resources, that's why it would be /admin/myrealm/api/clients/v2/clients and not /admin/myrealm/api/clients/v2. So we could also have /admin/myrealm/api/clients/v2/client-scopes. And because of this doubling ...clients/v2/clients the idea was to use clients-api instead of api/clients.
Does everybody agree that api groups have different types of resources?

@vmuzikar
Copy link
Contributor

After some offline discussion with @stianst, there are the following considerations:

  • API groups will be encapsulating just a single resource. So Clients API will be for clients management only, not scopes etc. As a result it is ok to have e.g. GET /admin/api/my-realm/clients/v2 for fetching all clients, and GET /admin/api/my-realm/clients/v2/my-client-id for fetching a single client.
  • To support the future hostname to realm name mapping, all resources and APIs will need to be associated with a realm. I.e. there will be no real "global resources". We want to avoid the need of artificial hostname for global resources. As a result we don't need /realms/ in the path.
    • Any resource that could be considered global will be either associated with the master realm (e.g. realms management), or with an arbitrary realm for given tenant (e.g. server info endpoint).
  • Admin URLs will need to be per realm in the future. This is to allow use cases like:
    • admin.my-realm.my-kc.org mapping to my-kc.local/admin/api/my-realm
    • my-realm.my-kc.org mapping to my-kc.local/my-realm
  • We won't be placing /admin/ after the realm name, it will be at the beginning of path.

So the proposal is:

  • Get clients: GET /admin/api/my-realm/clients/v2
  • Get single client: GET /admin/api/my-realm/clients/v2/my-client-id
  • Get realms: GET /admin/api/master/realms/v2 (future – out of scope of Client API efforts)
  • Get single realm: GET /admin/api/my-realm/realm/v2 (future)
  • Get server info: GET /admin/api/my-realm/server-info (future)

@stianst Does that accurately capture the discussion we had earlier?

@shawkins
Copy link
Contributor

API groups will be encapsulating just a single resource. So Clients API will be for clients management only, not scopes etc. As a result it is ok to have e.g. GET /admin/api/my-realm/clients/v2 for fetching all clients, and GET /admin/api/my-realm/clients/v2/my-client-id for fetching a single client.

While this adds more flexibility over a global version, I would add:

  • we should avoid like the plague adding additional versions. Whenever possible we should evolve, not immediately break the schema.
  • it could be more confusing than with api groups to introduce a new resource type. Does its version relate to the other existing versions - will it start at v1, v2, etc.?
  • you may still end up needing to coordianate breaking changes across highly related resource types

Also it would be good to clarify with any non-global versioning scheme what the relationship is to the feature version. In the prototype we have just a single feature version for the entire admin api.

Related to this how, or should, admins be able to configure which serving versions are available?

We want to avoid the need of artificial hostname for global resources. As a result we don't need /realms/ in the path.

Having api in the path serves a similar purpose - it's a sibling to the v1 /admin/realms

So the proposal is:

From a client perspective needing to have specialized URL construction handling for a single realm isn't ideal, but it's also not that difficult to manage.

For the future it could be good to version server-info as well.

Finally just like with other proposals, there's still a potential v1 conflict, this time with admin/api/console - but as of now we haven't proposed to actually have anything served of that endpoint so it's probably ok to ignore this.

@sschu
Copy link
Contributor

sschu commented Dec 18, 2025

Do we need the /api? Is there any case where we wouldn't have /api after /admin? I am wondering if that could interfere with current URLs like if somebody calls a realm api and the path to its admin console would be /admin/api/console? If we leave the api out, we would always have the realm name after /admin.

@vmuzikar
Copy link
Contributor

@shawkins As for the versioning concerns. I see each API version also a Feature version, i.e. you can selectively enable/disable the API versions. To do that we'll need to add the ability to enable multiple Feature versions simultaniously. But that's for the future, right now we have a single Client API feature.

Any subresources will be part of the parent resource API group. Adjacent resources (e.g. users and roles) will use separate API groups with independent versioning, but can use key references to the other resource as we don't expect keys would ever be affected by version bumps.

@shawkins @sschu The potential conflict with /admin/api/console can be solved by the Content-Type header.

@shawkins
Copy link
Contributor

shawkins commented Dec 18, 2025

I see each API version also a Feature version, i.e. you can selectively enable/disable the API versions.

Ok, so we'll have an admin api v1 feature, then a v(1+n) feature for each root resource type, and there is no presumed relationship between the same versions of different resources. If we add a new resource type, it will likely start at v2 to avoid confusion with the global v1 designation.

To do that we'll need to add the ability to enable multiple Feature versions simultaniously.

In general this reinforces the need to minimize additional versions - adding support for version ranges, min versions, etc. will add even more complexity on top of adding a lot of features.

but can use key references to the other resource as we don't expect keys would ever be affected by version bumps.

This is true, but can still be confusing. Again with the case of adding a new type - if you need to reference that from an existing type, having to independently manage those versions is less than optimal.

@shawkins @sschu The potential conflict with /admin/api/console can be solved by the Content-Type header.

It's probably good to note that v1 already has degenerate cases - a realm named realms, serverinfo, or console.

If for example you create a realm called realms, then issue GET /admin/realms/console - the resteasy path matching logic will resolve that to AdminRoot.getRealmsAdmin, not getAdminConsole. Content-Type nor Accept headers come into play as neither operation is looking for them, and those do seem to be one of the last considerations in general.

We all agree the v2 proposal adds api to the problematic set of realm names. In addition to the html expected from GET /admin/api/console, subpaths under console expect and produce different media types. While I don't see any conflict yet with v2 resources, it seems like it will be more complicated to address than adding produces / consumes to v1 / v2 methods and could further complicate things down the road. It's not ideal but if worst comes to worst we can just say that api was an unfortunate naming choice for a realm - just as realms, serverinfo, and console currently are.

@vmuzikar
Copy link
Contributor

Ok, so we'll have an admin api v1 feature, then a v(1+n) feature for each root resource type, and there is no presumed relationship between the same versions of different resources. If we add a new resource type, it will likely start at v2 to avoid confusion with the global v1 designation.

Yes, correct.

In general this reinforces the need to minimize additional versions

Yeah, introducing a new API version should be a rare event.

if you need to reference that from an existing type, having to independently manage those versions is less than optimal.

Could you elaborate on that?

We all agree the v2 proposal adds api to the problematic set of realm names. In addition to the html expected from GET /admin/api/console, subpaths under console expect and produce different media types. While I don't see any conflict yet with v2 resources, it seems like it will be more complicated to address than adding produces / consumes to v1 / v2 methods and could further complicate things down the road. It's not ideal but if worst comes to worst we can just say that api was an unfortunate naming choice for a realm - just as realms, serverinfo, and console currently are.

I think we can't fully avoid the risk of conflicts– with or without /api/ in the path.

@shawkins
Copy link
Contributor

Could you elaborate on that?

With api groups you shouldn't have references in one resource to other resources in the group that don't exist in that version.

Let's say we have an api group with version v1 and v2. v2 adds a new resource and that is referenced in a v2 resource that has both a v1 and a v2 version. Everything in my highly related api group is logcally consistent at v2. Fetching the v1 form of the exisitng resource shouldn't even have that new reference present - because it wouldn't be consistent.

When you start developing against our fine-grained version management you'll basically be creating a version lock file:

realms=v2
clients=v3
roles=v2
users=v2
...

Based upon the latest versions supported by the Keycloak you initially target for development against.

From there the developer will be responsible for individually updating these versions. And if you for example want to start using new resource v2, that may also require you to update to users=v3 - not an obvious relationship.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

team/admin-api-wg Admin API v2 Working Group team/cloud-native

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Every distinct Admin API should be versioned

5 participants