【问题标题】:Google API Oauth2 Refresh token bad request 400Google API Oauth2 刷新令牌错误请求 400
【发布时间】:2021-07-11 14:49:23
【问题描述】:

使用带有 Xamarin C# 的 Google API 刷新现有令牌时遇到问题。我猜我的代码有问题,但我找不到。

(注意:我在 & 处添加了换行符以使请求更具可读性。希望每个人都会对此感到满意。)

请求身份验证 URI

https://accounts.google.com/o/oauth2/v2/auth?
scope=https://www.googleapis.com/auth/calendar https://www.googleapis.com/auth/calendar.events&
include_granted=true&
response_type=code&
redirect_uri=com.googleusercontent.apps.MYOAUTHCLIENTID:/oauth2redirect&
client_id=MYOAUTHCLIENTID.apps.googleusercontent.com&
access_type=offline

重定向 URI

com.googleusercontent.apps.MYOAUTHCLIENTID:/oauth2redirect

响应验证码

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

请求令牌 URI

https://oauth2.googleapis.com/token?
code=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&
redirect_uri=com.googleusercontent.apps.MYOAUTHCLIENTID:/oauth2redirect&
client_id=MYOAUTHCLIENTID.apps.googleusercontent.com&
grant_type=authorization_code

响应令牌

{
  "access_token": "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY",
  "expires_in": 3599,
  "refresh_token": "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ",
  "scope": "https://www.googleapis.com/auth/calendar https://www.googleapis.com/auth/calendar.events",
  "token_type": "Bearer"
}

现在我可以在我的 HTTP 标头请求中使用“access_token”并毫无问题地使用日历。我也可以撤销令牌,但不能刷新它。

尝试刷新令牌

var dict = new Dictionary<string, string>();
dict.Add("Content-Type", "application/x-www-form-urlencoded");
var contentHeader = new FormUrlEncodedContent(dict);

HttpClient refreshTokenClient = new HttpClient();

// Doing this because someone wrote that this helped in his case. Did not help :/
System.Net.ServicePointManager.SecurityProtocol |=
    SecurityProtocolType.Tls12 |
    SecurityProtocolType.Tls11 |
    SecurityProtocolType.Tls;

// uriTokenRequest has the type URI with this value
// {https://oauth2.googleapis.com/token?
// code=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&
// client_id=MYOAUTHCLIENTID.apps.googleusercontent.com&
// grant_type=refresh_token&
// refresh_token=ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ}

using (var result = await refreshTokenClient.PostAsync(uriTokenRequest, contentHeader))
    if (result.IsSuccessStatusCode) // This will be FALSE
    {
        ...
    }

回应

{StatusCode: 400, ReasonPhrase: 'Bad Request', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
  Accept-Ranges: none
  Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
  Cache-Control: no-store, must-revalidate, no-cache, max-age=0
  Date: Sun, 11 Jul 2021 13:46:09 GMT
  Pragma: no-cache
  Server: scaffolding
  Server: on
  Server: HTTPServer2
  Transfer-Encoding: chunked
  Vary: X-Origin
  Vary: Referer
  Vary: Origin
  Vary: Accept-Encoding
  X-Android-Received-Millis: 1626011170088
  X-Android-Response-Source: NETWORK 400
  X-Android-Selected-Protocol: http/1.1
  X-Android-Sent-Millis: 1626011170050
  X-Content-Type-Options: nosniff
  X-Frame-Options: SAMEORIGIN
  X-XSS-Protection: 0
  Content-Type: application/json; charset=utf-8
  Expires: Mon, 01 Jan 1990 00:00:00 GMT
}}

Google API 文档https://developers.google.com/identity/protocols/oauth2/native-app#offline 确实提到了“client_secret”。但是对于 response_type “代码”,我从来没有收到过这样的。我现在已经阅读了很多次文档,以至于我对它视而不见。

或者“代码”不需要令牌刷新?

有什么想法吗?

编辑:“代码”确实需要令牌刷新,因为令牌确实过期了,正如结果属性“expires_in”已经说明的那样。

编辑 2:正如 Cherry Bu 所说,MSFT 建议我查看 Xamarin.Auth 源代码并发现一些差异,我对此进行了调整。不幸的是,我仍然无法成功。这是我最近的尝试:

var queryValues = new Dictionary<string, string>();
//queryValues.Add("Content-Type", "application/x-www-form-urlencoded");
queryValues.Add("client_id", Constants.OAuthClientId);
queryValues.Add("code", _authenticationCode);
queryValues.Add("refresh_token", _refresh_token);
queryValues.Add("grant_type", "refresh_token");

var httpContent = new FormUrlEncodedContent(queryValues);

HttpClient refreshTokenClient = new HttpClient();

//if (!string.IsNullOrEmpty(_accessToken) && !string.IsNullOrEmpty(_accessTokenType))
//{
//    refreshTokenClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(_accessTokenType, _accessToken);
//}

using (var response = await refreshTokenClient.PostAsync("https://accounts.google.com/o/oauth2/token", httpContent).ConfigureAwait(false))
{
    if (response.IsSuccessStatusCode) --> This will be false
    {
        ...
    }
}

【问题讨论】:

  • 搜索一些关于通过Xamarin使用Google API刷新现有令牌的信息,找到一篇使用Xamarin.Auth实现Oauth2的文章。然后Xamarin.Auth组件支持将令牌存储在设备上,覆盖GetInitialUrlAsync method to request a refresh token,最后创建一个方法来请求我们的刷新令牌。
  • 好主意。谢谢你的提示。不幸的是,我无法使用 Xamarin.Auth 感知包依赖问题。这就是我自己写所有东西的原因。我会按照你的建议检查 Xamarin.Auth 的源代码。
  • 期待您的更新。

标签: c# xamarin google-api google-oauth


【解决方案1】:

刷新访问令牌的正确http端点可以在下面找到

HTTP POST  https://accounts.google.com/o/oauth2/token
client_id={ClientId}&client_secret={ClientSecret}&refresh_token=1/ffYmfI0sjR54Ft9oupubLzrJhD1hZS5tWQcyAvNECCA&grant_type=refresh_token

我实际上有一个使用带有 Xamarin 的 google .net 客户端库的示例,我必须调整授权来适应它。我去看看能不能找到代码。

【讨论】:

  • 感谢您的回答。如果你能把代码sn-p分享给我,那就太酷了。我已经看到您使用不同的 url 进行通话,然后我这样做了。此外,您正在使用“client_secret”,但使用“代码”我从未收到过此类信息。
  • 我试过知道https://accounts.google.com/o/oauth2/token?code=XXXXXX&amp; client_id=MYCLIENTID.apps.googleusercontent.com&amp;grant_type=refresh_token&amp;refresh_token=1//03hm4kzQ-AdYYYYY,但不幸的是问题仍然存在。
【解决方案2】:

修复它。 2个问题:

1 DefaultRequestHeader 不起作用。

HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(GoogleOAuth.AccessToken, GoogleOAuth.AccessTokenType);

即使对象本身看起来不错,它也不起作用。我用那个替换它:

HttpClient client = new HttpClient();
var requestMessage = new HttpRequestMessage(HttpMethod.Post, calenderUri);
requestMessage.Headers.Authorization = new AuthenticationHeaderValue(GoogleOAuth.AccessTokenType, GoogleOAuth.AccessToken); // both are strings. ("Bearer", "yaa...")
requestMessage.Content = data;
var response = await client.SendAsync(requestMessage);

if (!response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
throw new Exception(content);
}

在那之后我只需要再做一件事

2 从请求数据中删除了“code”和“client_secret”。结果:

using (HttpClient client = new HttpClient())
{
    var googleData = new Dictionary<string, string>();
    googleData.Add("client_id", GoogleOAuth.ClientId);
    googleData.Add("refresh_token", GoogleOAuth.RefreshToken);
    googleData.Add("grant_type", "refresh_token");

    var data = new FormUrlEncodedContent(googleData);

    var requestMessage = new HttpRequestMessage(HttpMethod.Post, Constants.GoogleTokenUri);
    requestMessage.Headers.Authorization = new AuthenticationHeaderValue(GoogleOAuth.AccessTokenType, GoogleOAuth.AccessToken);
    requestMessage.Content = data;
    var response = await client.SendAsync(requestMessage);

    if (response.IsSuccessStatusCode)
    {
        // do something
    }
}

几个星期以来,我都试图让它运行起来,但几乎是精神错乱。希望这可以节省一些人的神经。

【讨论】:

    猜你喜欢
    • 2019-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-14
    • 2016-08-03
    • 2016-12-03
    • 2013-07-21
    相关资源
    最近更新 更多