diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ClientInitialAccessResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ClientInitialAccessResource.java index f43bbdad174..245fd492d97 100644 --- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ClientInitialAccessResource.java +++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ClientInitialAccessResource.java @@ -27,6 +27,7 @@ import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; import org.keycloak.representations.idm.ClientInitialAccessCreatePresentation; import org.keycloak.representations.idm.ClientInitialAccessPresentation; @@ -40,7 +41,12 @@ public interface ClientInitialAccessResource { @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) ClientInitialAccessPresentation create(ClientInitialAccessCreatePresentation rep); - + + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + Response doCreate(ClientInitialAccessCreatePresentation rep); + @GET @Produces(MediaType.APPLICATION_JSON) List list(); diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientInitialAccessResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientInitialAccessResource.java index 4d815107199..8add10fac17 100644 --- a/services/src/main/java/org/keycloak/services/resources/admin/ClientInitialAccessResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientInitialAccessResource.java @@ -26,13 +26,11 @@ import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import org.keycloak.events.admin.OperationType; import org.keycloak.events.admin.ResourceType; -import org.keycloak.http.HttpResponse; import org.keycloak.models.ClientInitialAccessModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; @@ -83,7 +81,7 @@ public class ClientInitialAccessResource { @Tag(name = KeycloakOpenAPI.Admin.Tags.CLIENT_INITIAL_ACCESS) @Operation( summary = "Create a new initial access token.") @APIResponse(responseCode = "201", description = "Created", content = @Content(schema = @Schema(implementation = ClientInitialAccessCreatePresentation.class))) - public Object create(ClientInitialAccessCreatePresentation config) { + public Response create(ClientInitialAccessCreatePresentation config) { auth.clients().requireManage(); int expiration = config.getExpiration() != null ? config.getExpiration() : 0; @@ -106,12 +104,10 @@ public class ClientInitialAccessResource { String token = ClientRegistrationTokenUtils.createInitialAccessToken(session, realm, clientInitialAccessModel, config.getWebOrigins()); rep.setToken(token); - HttpResponse response = session.getContext().getHttpResponse(); - - response.setStatus(Response.Status.CREATED.getStatusCode()); - response.addHeader(HttpHeaders.LOCATION, session.getContext().getUri().getAbsolutePathBuilder().path(clientInitialAccessModel.getId()).build().toString()); - - return rep; + return Response.status(Response.Status.CREATED) + .entity(rep) + .location(session.getContext().getUri().getAbsolutePathBuilder().path(clientInitialAccessModel.getId()).build()) + .build(); } @GET diff --git a/tests/base/src/test/java/org/keycloak/tests/admin/InitialAccessTokenResourceTest.java b/tests/base/src/test/java/org/keycloak/tests/admin/InitialAccessTokenResourceTest.java index 8112899bf5f..e44b3291cab 100644 --- a/tests/base/src/test/java/org/keycloak/tests/admin/InitialAccessTokenResourceTest.java +++ b/tests/base/src/test/java/org/keycloak/tests/admin/InitialAccessTokenResourceTest.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.stream.Collectors; import jakarta.ws.rs.BadRequestException; +import jakarta.ws.rs.core.Response; import org.keycloak.admin.client.resource.ClientInitialAccessResource; import org.keycloak.common.util.Time; @@ -154,6 +155,28 @@ public class InitialAccessTokenResourceTest { } } + @Test + public void testCreateReturns201WithLocationHeader() { + ClientInitialAccessCreatePresentation rep = new ClientInitialAccessCreatePresentation(); + rep.setCount(1); + rep.setExpiration(100); + + String id; + try (Response response = resource.doCreate(rep)) { + assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatus()); + + String location = response.getHeaderString("Location"); + assertNotNull(location, "Location header must be present on 201 Created"); + + ClientInitialAccessPresentation entity = response.readEntity(ClientInitialAccessPresentation.class); + id = entity.getId(); + assertNotNull(id); + assertNotNull(entity.getToken()); + assertThat(location, org.hamcrest.Matchers.endsWith("/clients-initial-access/" + id)); + } + resource.delete(id); + } + private void removeExpired(String realmUuid) { runOnServer.run(session -> { RealmModel realm = session.realms().getRealm(realmUuid);