Google oauth java 客户端获取访问令牌失败,并显示“400 Bad Request {“error”:“invalid_request”}”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13638758/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 13:28:32  来源:igfitidea点击:

Google oauth java client to get an access token fails with "400 Bad Request { "error" : "invalid_request" }"

javaoauth-2.0google-oauth

提问by Sap

I am using "web server applications" example shown here. In my callback servlet I want to retrieve an access token but I am not able to successfully do it. Following is my code

我正在使用此处显示的“Web 服务器应用程序”示例。在我的回调 servlet 中,我想检索访问令牌,但我无法成功完成。以下是我的代码

  @Override
  protected String getUserId(HttpServletRequest req) throws ServletException, IOException {
    // return user ID
      Iterator<String> iterator = req.getParameterMap().keySet().iterator();
        while (iterator.hasNext()) {
            String string = iterator.next();

            System.out.println(string+"---++--"+req.getParameter(string));
        }
        GoogleAuthorizationCodeTokenRequest newTokenRequest = new GoogleAuthorizationCodeFlow.Builder(new NetHttpTransport(), new HymansonFactory(),
                                                             "2XXXXXX7218.apps.googleusercontent.com", "KugD_XXX_7vqnGZVXXXXX1M",
                                                              Collections.singleton("https://gdata.youtube.com"))
                                                              .build().newTokenRequest(req.getParameter("code"));
        //GoogleAuth
        GoogleTokenResponse token = newTokenRequest.setRedirectUri("/").execute();
        String accessToken = token.getAccessToken();
        System.out.println("accesstoken:"+accessToken);
        return "";
  }

After running this code I am getting following error

运行此代码后,我收到以下错误

com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
{
  "error" : "invalid_request"
}

In a nutshell I am getting the "code" parameter(request code) I am not sure how to convert it to Access token. I have already seen Google API - request for token from Oauth2 returns "invalid_request"Google OAuth 2: response_type error on token requestbut there wan't much I could use in my code

简而言之,我得到了“代码”参数(请求代码),我不确定如何将其转换为访问令牌。我已经看到了 Google API - 来自 Oauth2 的令牌请求返回“invalid_request” Google OAuth 2: response_type error on token request但是我可以在我的代码中使用的东西不多

EDIT

编辑

The google API did not work for me so I wrote following code without using any library

谷歌 API 对我不起作用,所以我在不使用任何库的情况下编写了以下代码

 URL url = new URL("https://accounts.google.com/o/oauth2/token");
    connection = (HttpURLConnection) url.openConnection();
    String urlParameters = "code=" + req.getParameter("code") + "&client_id=29852.apps.googleusercontent.com&client_secret=KugD_LVi_7vqnssssxxxNRBz1M"+
            "&redirect_uri=https://flixomnia.com/oauth2callback&grant_type=authorization_code&scope=https://gdata.youtube.com&response_type=token";
    connection.setDoOutput(true);
    connection.setDoInput(true);
    connection.setInstanceFollowRedirects(true);
    connection.setRequestMethod("POST");
    connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
    connection.setRequestProperty("Authorization", "Bearer 4/q3Xh_pJI458XXXXXXXkh-lxe3-8.cmaD6o7V5BkQXE-XXXXX-edgI");
    connection.setRequestProperty("Content-Length", "" + Integer.toString(urlParameters.getBytes().length));
    connection.setRequestProperty("X-GData-Key", "key=AI39siXXXXXXM7tyHBvXEM1lLcORetit6QSArQ3sjelBxXXXXXXtgLSPdZPxvsF_vkntOQMnAEYAuVFqhN7oUw");
    connection.setRequestProperty("GData-Version", "2");

    connection.setUseCaches(false);
    //com.google.gdata.client.youtube.YouTubeService service = new com.google.gdata.client.youtube.YouTubeService("","");
    //YouTubeMediaGroup g = new YouTubeMediaGroup();


    DataOutputStream wr = new DataOutputStream(connection.getOutputStream());

    wr.writeBytes(urlParameters);
    wr.flush();
    InputStream inputStream = connection.getInputStream();
    byte[] b = new byte[1024];
    while (inputStream.read(b) != -1) {
        System.out.print(new String(b));

    }
    System.out.println("");
    wr.close();
    connection.disconnect();

But still I get following error

但我仍然收到以下错误

    {  "error" : "invalid_request"}
java.io.IOException: Server returned HTTP response code: 400 for URL: https://accounts.google.com/o/oauth2/token
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1615)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
    at com.broadcastr.servlets.YouTubeCallbackService.getUserId(YouTubeCallbackService.java:168)
    at com.google.api.client.extensions.servlet.auth.oauth2.AbstractAuthorizationCodeCallbackServlet.doGet(AbstractAuthorizationCodeCallbackServlet.java:130)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1001)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:579)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:722)

回答by Vars

  1. In the setRedirectUrimethod in the initial code above to get the access token, the redirect_uriis not set correctly. The redirect_urithat is specified at the time of client registration should be used.

  2. In the EDIT code, while sending the required parameters to the access token end-point, an unsupported parameter response_typeis also being sent along with the request. Removing the response_typeparameter should solve the purpose.

    Also, according to the OAuth2 RFC draft, the access token end-point might also error out invalid_requestif the request utilizes more than one mechanism to authenticate the client. So, removing the Authorizationheader to the URLConnectionshould also solve the purpose.

  1. setRedirectUri上面初始代码中获取访问令牌的方法中,redirect_uri没有正确设置。的redirect_uri是在客户机登记时指定应该被使用。

  2. 在 EDIT 代码中,在向访问令牌端点发送所需参数的同时,不支持的参数response_type也随请求一起发送。删除response_type参数应该可以解决目的。

    此外,根据OAuth2 RFC 草案invalid_request如果请求使用一种以上的机制来验证客户端,访问令牌端点也可能出错。因此,将Authorization标题删除到URLConnection也应该可以解决目的。

回答by Deepika

I also wasted my 2 days solving this issue. I was not able to post token request using HttpUrlConnection. HttpClientworked for me.

我也浪费了我 2 天的时间来解决这个问题。我无法使用HttpUrlConnection. HttpClient对我来说有效。

Following is working code:

以下是工作代码:

1) Value passed:

1) 传递的值:

String url = "https://accounts.google.com/o/oauth2/token";
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
nameValuePairs.add(new BasicNameValuePair("grant_type", "authorization_code"));

nameValuePairs.add(new BasicNameValuePair("client_id",client_id));
nameValuePairs.add(new BasicNameValuePair("client_secret", client_secret));
nameValuePairs.add(new BasicNameValuePair("redirect_uri", "http://example.com/bin/showcase/servlet/googlecallback"));
nameValuePairs.add(new BasicNameValuePair("code", code));

StringBuffer postResult =  sendPost(url, nameValuePairs);

2) Method

2) 方法

private StringBuffer sendPost(String url, List<NameValuePair> postParams) 
        throws Exception {

    HttpPost post = new HttpPost(url);
    HttpClient client = new DefaultHttpClient();

    // add header
    post.setHeader("Host", "accounts.google.com");
    post.setHeader("Accept", 
            "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
    post.setHeader("Accept-Language", "en-US,en;q=0.5");
    post.setHeader("Connection", "keep-alive");
    post.setHeader("Referer", "https://accounts.google.com/o/oauth2/token");
    post.setHeader("Content-Type", "application/x-www-form-urlencoded");

    post.setEntity(new UrlEncodedFormEntity(postParams));

    HttpResponse response = client.execute(post);

    int responseCode = response.getStatusLine().getStatusCode();

    BufferedReader rd = new BufferedReader(
            new InputStreamReader(response.getEntity().getContent()));

    StringBuffer result = new StringBuffer();
    String line = "";`enter code here`
    while ((line = rd.readLine()) != null) {
        result.append(line);
    }
    return result;
}

回答by David Primmer

Richard above is right, in setRedirectUri you need to use the full redirect URI that you specified when you registered your application. That should not be relative, but absolute. (and hopefully https)

上面的理查德是对的,在 setRedirectUri 中,您需要使用您在注册应用程序时指定的完整重定向 URI。这不应该是相对的,而是绝对的。(希望是 https)

davep

戴维普

回答by Richard Berger

In getting a Java app and an Android app to access my Oauth server, I found the two following libraries useful - but they serve different purposes - perhaps one is better suited to your needs than the other.

在让 Java 应用程序和 Android 应用程序访问我的 Oauth 服务器时,我发现以下两个库很有用 - 但它们用于不同的目的 - 也许一个比另一个更适合您的需求。

  1. google-oauth-java-client Used in DailyMotion. https://code.google.com/p/google-oauth-java-client/, http://samples.google-oauth-java-client.googlecode.com/hg/dailymotion-cmdline-sample/instructions.htmlThis library/sample code allows you to access your own OAuth2 server from Java.

  2. google-api-java-client Used in: Auth2 flow in Android (Latitude) http://blog.doityourselfandroid.com/2011/08/06/oauth-2-0-flow-android/This library/sample code is specifically for accessing Google APIs through OAuth2.

  1. google-oauth-java-client 在 DailyMotion 中使用。 https://code.google.com/p/google-oauth-java-client/, http://samples.google-oauth-java-client.googlecode.com/hg/dailymotion-cmdline-sample/instructions.html此库/示例代码允许您从 Java 访问您自己的 OAuth2 服务器。

  2. google-api-java-client 用于:Android(Latitude)中的Auth2流http://blog.doityourselfandroid.com/2011/08/06/oauth-2-0-flow-android/这个库/示例代码是专门用于通过 OAuth2 访问 Google API。

I am not sure which problem you are trying to solve, but one of those two should help. Both go through the process of exchanging a "code" for an "authToken", but in slightly different manner. RB

我不确定您要解决哪个问题,但这两个问题之一应该会有所帮助。两者都经历了将“代码”交换为“authToken”的过程,但方式略有不同。RB

回答by Manish Prajapati

please remove the "&response_type=token" parameter from request URL that is problem in EDIT code and your problem get solved.

请从编辑代码中存在问题的请求 URL 中删除“&response_type=token”参数,您的问题就会得到解决。