英文:
Oauth2 token call failing with "request is missing a required parameter"
问题
private String tokenEndpoint = "https://xxxxxxxxxxxxx/oauth2/token";
private String client_id = "2xxxxxxxxxxxxxxxxx";
private String client_secret = "xxxxxxxxxxxxxxxxxxxx";
private String grant_type = "client_credentials";
private String scope = "projects:read";
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
.loadTrustMaterial(null, acceptingTrustStrategy)
.build();
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(csf)
.build();
HttpPost httpPost = new HttpPost(tokenEndpoint);
String base64Credentials = Base64.getEncoder().encodeToString((client_id + ":" + client_secret).getBytes());
httpPost.addHeader("Authorization","Bearer " + base64Credentials);
httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded");
StringEntity input = null;
try {
input = new StringEntity("grant_type=" + grant_type + "&scope=" + scope);
httpPost.setEntity(input);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
String result = IOUtils.toString(response.getEntity().getContent(), "UTF-8");
OAuthClient oauthClient = new OAuthClient();
String res = oauthClient.callService();
System.out.println(res);
英文:
I'm trying to connect to the REST API using application/x-www-form-urlencoded
,
using the following parameters:
private String tokenEndpoint = "https://xxxxxxxxxxxxx/oauth2/token";
private String client_id = "2xxxxxxxxxxxxxxxxx";
private String client_secret = "xxxxxxxxxxxxxxxxxxxx";
private String grant_type = "client_credentials";
private String scope = "projects:read";
and finally get the following error:
>{"error":"invalid_request","error_description":"The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Client credentials missing or malformed in both HTTP Authorization header and HTTP POST body."}
My code is:
package testRestAPI;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.cert.X509Certificate;
import java.util.Base64;
import javax.net.ssl.SSLContext;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.TrustStrategy;
public class OAuthClient {
private String tokenEndpoint = "https://xxxxxxxxxxxxx/oauth2/token";
private String client_id = "2xxxxxxxxxxxxxxxxx";
private String client_secret = "xxxxxxxxxxxxxxxxxxxx";
private String grant_type = "client_credentials";
private String scope = "projects:read";
public String callService() {
String result = null;
try {
//My site is set as insecure, so I set the following setting
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
.loadTrustMaterial(null, acceptingTrustStrategy)
.build();
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(csf)
.build();
/* HTTPCLIENT AND HTTPPOST OOBJECT */
// HttpClient httpClient = HttpClientBuilder.create().build();
HttpPost httpPost = new HttpPost(tokenEndpoint);
/* AUTHENTICATION CREDENTIALS ENCODING */
String base64Credentials = Base64.getEncoder().encodeToString((client_id + ":"
+ client_secret).getBytes());
/* HEADER INFO */
httpPost.addHeader("Authorization","Bearer " + base64Credentials);
httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded");
// /* PROXY CONFIG */
// HttpHost target = new HttpHost("proxy", 8080, "http");
// RequestConfig config = RequestConfig.custom().setProxy(target).build();
// httpPost.setConfig(config);
/* OAUTH PARAMETERS ADDED TO BODY */
StringEntity input = null;
try {
input = new StringEntity("grant_type=" + grant_type + "&scope=" + scope);
httpPost.setEntity(input);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
/* SEND AND RETRIEVE RESPONSE */
HttpResponse response = null;
try {
response = httpClient.execute(httpPost);
} catch (IOException e) {
e.printStackTrace();
}
/* RESPONSE AS STRING */
// String result = null;
try {
result = IOUtils.toString(response.getEntity().getContent(), "UTF-8");
} catch (IOException e) {
e.printStackTrace();
}
}
catch (Exception e) {
// TODO: handle exception
}
return result;
}
public static void main(String[] args) {
OAuthClient oauthClient = new OAuthClient();
String res = oauthClient.callService();
System.out.println(res);
}
}
and finally get the following error:
> {"error":"invalid_request","error_description":"The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Client credentials missing or malformed in both HTTP Authorization header and HTTP POST body."}
In Postman the connection is made successfully.Connection with Postman
答案1
得分: 0
以下是翻译好的内容:
主要问题是您未在表单中包含client_id和client_secret。我注意到使用Fiddlr时,Postman会在提交的表单上发送所有这些字段。
改进代码的其他更改,但可能不需要修复的问题包括:
-
删除无意义的Authorization Bearer标头。Postman不会发送,也没有意义发送该标头,直到接收到令牌为止。
-
用标准的
UrlEncodedFormEntity
替换自制的表单模拟,并传递一个List<NameValuePair>
。它会将"Content-Type", "application/x-www-form-urlencoded"
标头添加到请求中。
请尝试以下代码:
import java.io.IOException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import javax.net.ssl.SSLContext;
import org.apache.commons.io.IOUtils;
import org.apache.http.Consts;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.TrustStrategy;
public class OAuthClient {
private String tokenEndpoint = "https://xxxxxxxxxxxxx/oauth2/token";
private String client_id = "2xxxxxxxxxxxxxxxxx";
private String client_secret = "xxxxxxxxxxxxxxxxxxxx";
private String grant_type = "client_credentials";
private String scope = "projects:read";
public String callService() {
String result = null;
try {
// My site is set as insecure, so I set the following setting
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
.loadTrustMaterial(null, acceptingTrustStrategy)
.build();
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(csf)
.build();
/* HTTPCLIENT AND HTTPPOST OOBJECT */
HttpPost httpPost = new HttpPost(tokenEndpoint);
/* OAUTH PARAMETERS ADDED TO FORM */
List<NameValuePair> form = new ArrayList<>();
form.add(new BasicNameValuePair("grant_type", grant_type));
form.add(new BasicNameValuePair("scope", scope));
form.add(new BasicNameValuePair("client_id", client_id)); // these two were missing
form.add(new BasicNameValuePair("client_secret", client_secret));
// UrlEncodedFormEntity is the standard way of building a form submission
// and it removes the need to manually add the "Content-Type", "application/x-www-form-urlencoded" header
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(form, Consts.UTF_8);
httpPost.setEntity(entity);
/* SEND AND RETRIEVE RESPONSE */
HttpResponse response = null;
try {
response = httpClient.execute(httpPost);
} catch (IOException e) {
e.printStackTrace();
}
/* RESPONSE AS STRING */
// String result = null;
try {
result = IOUtils.toString(response.getEntity().getContent(), "UTF-8");
} catch (IOException e) {
e.printStackTrace();
}
} catch (Exception e) {
// TODO: handle exception
}
return result;
}
public static void main(String[] args) {
OAuthClient oauthClient = new OAuthClient();
String res = oauthClient.callService();
System.out.println(res);
}
}
英文:
There are a couple of issues with your code.
Primarily, you are not including the client_id and client_secret in the form. I observed with Fiddlr that Postman sends all these fields on a submitted form.
Other changes to improve, but probably not required to fix the code are to:
-
Remove the nonsense Authorization Bearer header. Postman does not
send and doesn't make sense to send one until a token has been
received. -
Replaced the home-made form emulation and replaced with the standard
UrlEncodedFormEntity
passing aList<NameValuePair>
. It adds the"Content-Type", "application/x-www-form-urlencoded"
header to the request.
Try this:
import java.io.IOException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import javax.net.ssl.SSLContext;
import org.apache.commons.io.IOUtils;
import org.apache.http.Consts;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.TrustStrategy;
public class OAuthClient {
private String tokenEndpoint = "https://xxxxxxxxxxxxx/oauth2/token";
private String client_id = "2xxxxxxxxxxxxxxxxx";
private String client_secret = "xxxxxxxxxxxxxxxxxxxx";
private String grant_type = "client_credentials";
private String scope = "projects:read";
public String callService() {
String result = null;
try {
//My site is set as insecure, so I set the following setting
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
.loadTrustMaterial(null, acceptingTrustStrategy)
.build();
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(csf)
.build();
/* HTTPCLIENT AND HTTPPOST OOBJECT */
HttpPost httpPost = new HttpPost(tokenEndpoint);
/* OAUTH PARAMETERS ADDED TO FORM */
List<NameValuePair> form = new ArrayList<>();
form.add(new BasicNameValuePair("grant_type", grant_type));
form.add(new BasicNameValuePair("scope", scope));
form.add(new BasicNameValuePair("client_id", client_id)); // these two were missing
form.add(new BasicNameValuePair("client_secret", client_secret));
// UrlEncodedFormEntity is the standard way of building a firm submission
// and it removes the need to manually add the "Content-Type", "application/x-www-form-urlencoded" header
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(form, Consts.UTF_8);
httpPost.setEntity(entity);
/* SEND AND RETRIEVE RESPONSE */
HttpResponse response = null;
try {
response = httpClient.execute(httpPost);
} catch (IOException e) {
e.printStackTrace();
}
/* RESPONSE AS STRING */
// String result = null;
try {
result = IOUtils.toString(response.getEntity().getContent(), "UTF-8");
} catch (IOException e) {
e.printStackTrace();
}
}
catch (Exception e) {
// TODO: handle exception
}
return result;
}
public static void main(String[] args) {
OAuthClient oauthClient = new OAuthClient();
String res = oauthClient.callService();
System.out.println(res);
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论