From be6a3814fb803fc26751369cd7a162879b3f7dec Mon Sep 17 00:00:00 2001 From: Stian Thorgersen Date: Thu, 30 Oct 2025 12:12:08 +0100 Subject: [PATCH] Add CORS support to OIDC dynamic client registration endpoints (#43625) Closes #8863 Signed-off-by: stianst --- ...ClientInitialAccessCreatePresentation.java | 11 + .../securing-apps/client-registration.adoc | 12 + .../admin/messages/messages_en.properties | 2 + .../CreateInitialAccessToken.tsx | 20 ++ .../org/keycloak/http/simple/SimpleHttp.java | 2 + .../http/simple/SimpleHttpMethod.java | 2 +- .../http/simple/SimpleHttpRequest.java | 2 + .../java/org/keycloak/services/cors/Cors.java | 7 + .../AbstractClientRegistrationProvider.java | 15 +- .../ClientRegistrationTokenUtils.java | 25 +- .../InitialAccessToken.java | 13 + .../RegistrationAccessToken.java | 13 + .../oidc/OIDCClientRegistrationProvider.java | 35 ++- .../DefaultClientRegistrationPolicies.java | 7 +- .../impl/RegistrationWebOriginsPolicy.java | 58 +++++ .../RegistrationWebOriginsPolicyFactory.java | 38 +++ .../keycloak/services/cors/DefaultCors.java | 32 +++ .../admin/ClientInitialAccessResource.java | 2 +- .../resources/admin/ClientResource.java | 2 +- ...ion.policy.ClientRegistrationPolicyFactory | 3 +- .../testframework/realm/ManagedRealm.java | 21 ++ .../OIDCClientRegistrationCorsTest.java | 223 ++++++++++++++++++ 22 files changed, 520 insertions(+), 25 deletions(-) create mode 100644 services/src/main/java/org/keycloak/services/clientregistration/policy/impl/RegistrationWebOriginsPolicy.java create mode 100644 services/src/main/java/org/keycloak/services/clientregistration/policy/impl/RegistrationWebOriginsPolicyFactory.java create mode 100644 tests/base/src/test/java/org/keycloak/tests/client/OIDCClientRegistrationCorsTest.java diff --git a/core/src/main/java/org/keycloak/representations/idm/ClientInitialAccessCreatePresentation.java b/core/src/main/java/org/keycloak/representations/idm/ClientInitialAccessCreatePresentation.java index 27064ec5aa1..7228fb01c31 100644 --- a/core/src/main/java/org/keycloak/representations/idm/ClientInitialAccessCreatePresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/ClientInitialAccessCreatePresentation.java @@ -17,6 +17,8 @@ package org.keycloak.representations.idm; +import java.util.List; + /** * @author Stian Thorgersen */ @@ -26,6 +28,8 @@ public class ClientInitialAccessCreatePresentation { private Integer count; + private List webOrigins; + public ClientInitialAccessCreatePresentation() { } @@ -50,4 +54,11 @@ public class ClientInitialAccessCreatePresentation { this.count = count; } + public List getWebOrigins() { + return webOrigins; + } + + public void setWebOrigins(List webOrigins) { + this.webOrigins = webOrigins; + } } diff --git a/docs/guides/securing-apps/client-registration.adoc b/docs/guides/securing-apps/client-registration.adoc index 1959eee95bf..6d434d67221 100644 --- a/docs/guides/securing-apps/client-registration.adoc +++ b/docs/guides/securing-apps/client-registration.adoc @@ -74,6 +74,18 @@ If a client was created outside of the Client Registration Service it won't have You can create one through the admin console. This can also be useful if you lose the token for a particular client. To create a new token find the client in the admin console and click on `Credentials`. Then click on `Generate registration access token`. +=== Cross-Origin Resource Sharing (CORS) + +In case when clients are registered through the user-agent it is required to configure what web origins are permitted +for client registration. + +For bearer tokens the permitted web origin can be configured in the client the token was issued to. When creating an +initial access token, the permitted web origins can be supplied directly. + +For anonymous access, or as a realm wide configuration, permitted web origins can be configured by going to +clients, then client registration and updating the `Allowed Registration Web Origins` policy to list web origins +that should be allowed. + == {project_name} Representations The `default` client registration provider can be used to create, retrieve, update and delete a client. diff --git a/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties b/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties index e2e089f709b..f6281aaf385 100644 --- a/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties +++ b/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties @@ -1,6 +1,8 @@ cancel=Cancel deleteConfirm_other=Are you sure you want to delete these groups? trusted-hosts.label=Trusted Hosts +registration-web-origins.label=Allowed Registration Web Origins +registration-web-origins.tooltip=Allows CORS requests from the specified web origins deletedSuccess=Provider successfully deleted. searchAttributes=Search attributes userID=User ID diff --git a/js/apps/admin-ui/src/clients/initial-access/CreateInitialAccessToken.tsx b/js/apps/admin-ui/src/clients/initial-access/CreateInitialAccessToken.tsx index b9cfab72a03..23135ef3189 100644 --- a/js/apps/admin-ui/src/clients/initial-access/CreateInitialAccessToken.tsx +++ b/js/apps/admin-ui/src/clients/initial-access/CreateInitialAccessToken.tsx @@ -3,6 +3,7 @@ import { ActionGroup, AlertVariant, Button, + FormGroup, PageSection, } from "@patternfly/react-core"; import { useState } from "react"; @@ -18,6 +19,8 @@ import { ViewHeader } from "../../components/view-header/ViewHeader"; import { useRealm } from "../../context/realm-context/RealmContext"; import { toClients } from "../routes/Clients"; import { AccessTokenDialog } from "./AccessTokenDialog"; +import { MultiLineInput } from "../../components/multi-line-input/MultiLineInput"; +import { HelpItem } from "@keycloak/keycloak-ui-shared"; export default function CreateInitialAccessToken() { const { adminClient } = useAdminClient(); @@ -91,6 +94,23 @@ export default function CreateInitialAccessToken() { defaultValue: 1, }} /> + + } + > + +