Reputation: 1192
I am trying to make a POST request to a keycloak REST API endpoint with a body with application/x-www-form-urlencoded values.
Here is a cURL of a request:
curl -X POST \
https://auth.beyondtime-stage.io/auth/realms/master/protocol/openid-connect/token \
-H 'cache-control: no-cache' \
-H 'content-type: application/x-www-form-urlencoded' \
-d 'username=admin&password=pass123&client_id=admin-cli&grant_type=password'
To my disappointment, I haven't found a way to do it with feign.
Here is one example of what I've tried:
@FeignClient(name = "beyondtime-io-kc-client", url = "${btio.keycloakUrl}", path = "/")
public interface KeycloakAdminClient {
@PostMapping(name="realms/master/protocol/openid-connect/token", consumes = "application/x-www-form-urlencoded")
String getAuthToken(@RequestParam("username") String username,
@RequestParam("password") String password,
@RequestParam("client_id") String clientId,
@RequestParam("grant_type") String grantType);
}
In my pom.xml, I am using:
spring-cloud-starter-openfeign 2.1.1.RELEASE
I've also tried adding feign-form dependency and @Param instead of @RequestParam, but no success.
Upvotes: 4
Views: 12557
Reputation: 663
Sometimes those workarounds/hacks or actual implementation (as are defined by library itself) are more complex and boilerplated than it's necessary.
In this case I think it's easier and faster just to encode the body by yourself.
@FeignClient(name = "exampleClient", url = "https://example.com")
interface ExampleClient {
@PostMapping(
path = ["/oauth2/token"],
headers = ["Content-Type: application/x-www-form-urlencoded"],
consumes = [MediaType.APPLICATION_FORM_URLENCODED_VALUE],
)
fun loginWithCode(@RequestBody request: String): LoginResponse
}
val urlEncodedRequest = { code: String ->
mapOf(
"grant_type" to "authorization_code",
"client_secret" to "S3CR3T",
"client_id" to "0DFD0SF75F67DSA",
"code" to code,
).map { "${it.key}=${it.value}" }.joinToString("&")
}
The example is in Kotlin but the point is made.
Upvotes: 1
Reputation: 1192
I found the solution here How to POST form-url-encoded data with Spring Cloud Feign
Feign client:
import com.beyondtime.recruitmentservice.seafarer.entity.AuthTokenRequest;
import com.beyondtime.recruitmentservice.seafarer.entity.KeycloakAccessToken;
import feign.codec.Encoder;
import feign.form.spring.SpringFormEncoder;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@FeignClient(name = "beyondtime-io-kc-client", url = "${btio.keycloakUrl}", path = "/", configuration = KeycloakAdminClient.Configuration.class)
public interface KeycloakAdminClient {
@PostMapping(value="realms/master/protocol/openid-connect/token", consumes = "application/x-www-form-urlencoded")
KeycloakAccessToken getAuthToken(@RequestBody AuthTokenRequest authTokenRequest);
class Configuration {
@Bean
Encoder feignFormEncoder(ObjectFactory<HttpMessageConverters> converters) {
return new SpringFormEncoder(new SpringEncoder(converters));
}
}
}
Request object:
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class AuthTokenRequest {
private String username;
private String password;
private String client_id;
private String grant_type;
}
Response object:
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class KeycloakAccessToken {
@JsonProperty("access_token")
private String accessToken;
}
Upvotes: 7