android – Google OAuth2 – 访问令牌和刷新令牌 – > invalid_grant/Code已被兑换

我的目标是拥有某种长期访问令牌,以便我的Android应用程序可以在当天阅读用户Google日历的事件,而无需每次都获得用户批准.

我能够生成 – 我认为是 – 一次性授权代码;但是,当我将此发送到我的服务器端,应用程序引擎时,我收到以下错误响应:

400好的
{
  “错误”:“invalid_grant”,
  “error_description”:“代码已被兑换.”
}

这是被抛出的异常.我只是抓住它并将其作为一种调试方式发回给自己.

我得到的一次性代码以4 / VUr开头,所以我假设它是一次性代码而不是常规访问令牌.

目前,在Android上,我允许用户使用Google登录,以便我拥有自己的电子邮件地址.从那里我使用以下代码请求一次性授权代码:

try {
    Bundle appActivities = new Bundle();
    appActivities.putString(GoogleAuthUtil.KEY_REQUEST_VISIBLE_ACTIVITIES, "http://schemas.google.com/AddActivity");
    String scopes = "oauth2:server:client_id:" + Constants.SERVER_CLIENT_ID + ":api_scope:https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/calendar";
    //Plus.SCOPE_PLUS_LOGIN + " " + CalendarScopes.CALENDAR_READONLY;
    String acctName = "myGmail";
    String token = GoogleAuthUtil.getToken(getApplicationContext(), acctName, scopes, appActivities);

} catch (UserRecoverableAuthException e) {
        startActivityForResult(e.getIntent(), 257/*REQUEST_AUTHORIZATION/*/);
} catch (Exception e) {
        e.printStackTrace();
}

此代码来自here,似乎这是我必须做的.

然后我将此代码发送到我的App Engine端点.我使用here中的代码来请求访问和刷新令牌.

以下是我用作简单测试的代码:

HttpTransport transport = new NetHttpTransport();
JsonFactory jsonFactory = new JacksonFactory(); 
//ArrayList<String> scopes = new ArrayList<>();
//scopes.add("https://www.googleapis.com/auth/plus.login");
//scopes.add("https://www.googleapis.com/auth/calendar");

GoogleTokenResponse tokenResponse = new GoogleAuthorizationCodeTokenRequest(transport, jsonFactory,
                    SERVER_CLIENT_ID, SERVER_CLIENT_SECRET, code, "postmessage")/*.setScopes(scopes)*/.execute();

            //urn:ietf:wg:oauth:2.0:oob
            //postmessage
code = tokenResponse.getRefreshToken();

当我实例化GoogleAuthorizationCodeTokenRequest时,它失败了

仅举几例我看过
https://developers.google.com/accounts/docs/CrossClientAuth#offlineAccess
Google-api-php Refresh Token returns invalid_grant
getting Google oauth authorization token from Android- return with invalid_scope/ Unknown error

以不同方式设置重定向uri不起作用.
我确实为我的app引擎项目填写了同意屏幕.安装的Android客户端ID和Web应用程序客户端ID都在同一个项目中.对于我的应用,我将web应用程序的重定向uri设置为xxxxxxxx.appspot.com.

Gradle for my main app:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    //    compile 'com.google.api-client:google-api-client:1.18.0-rc'
    compile 'com.android.support:appcompat-v7:21.0.3'
    compile 'org.altbeacon:android-beacon-library:2.1.3'
    compile 'com.google.apis:google-api-services-calendar:v3-rev118-1.19.1'
    compile 'com.google.api-client:google-api-client-android:1.18.0-rc'
    compile 'com.google.android.gms:play-services:6.5.87'
    compile 'com.google.http-client:google-http-client-jackson:1.19.0'
    compile project(path: ':beaconBackend', configuration: 'android-endpoints')
}

Gradle for my backndnd:

dependencies {
    appengineSdk 'com.google.appengine:appengine-java-sdk:1.9.14'
    compile 'com.google.appengine:appengine-endpoints:1.9.14'
    compile 'com.google.appengine:appengine-endpoints-deps:1.9.14'
    compile 'javax.servlet:servlet-api:2.5'
}

真的很感激任何帮助!谢谢!

另请注意,我已尝试使当前访问令牌(或一次性代码?)无效/撤销.

我只需要一种方法来获得某种长生活访问令牌,而无需用户在第一次交互后进行交互.

最佳答案
自从我参与这个项目以来已经有一段时间了 – 不再需要了.

问题出在服务器端应用程序中.我只是没有正确地请求它.
一旦我的服务器端应用程序(App Engine Endpoint)从Android应用程序收到刷新令牌,我在服务器端执行了以下操作.

private String refreshAccessToken(String refreshToken, String clientId, String clientSecret) throws IOException {
    try {
        TokenResponse response =
                new GoogleRefreshTokenRequest(new NetHttpTransport(), new JacksonFactory(),
                        refreshToken, clientId, clientSecret).execute();
        return response.getAccessToken();
    } catch (TokenResponseException e) {
        return null;
    }
}

转载注明原文:android – Google OAuth2 – 访问令牌和刷新令牌 – > invalid_grant/Code已被兑换 - 代码日志