Google API Oauth2 刷新令牌错误请求 400
Google API Oauth2 Refresh token bad request 400
在 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 header 请求中使用“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
{
...
}
}
可以在下面找到刷新访问令牌的正确 http 端点
HTTP POST https://accounts.google.com/o/oauth2/token
client_id={ClientId}&client_secret={ClientSecret}&refresh_token=1/ffYmfI0sjR54Ft9oupubLzrJhD1hZS5tWQcyAvNECCA&grant_type=refresh_token
我实际上有一个将 google .net 客户端库与 Xamarin 一起使用的示例,我必须调整授权以适应它。我会四处看看是否能找到代码。
已修复。 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 从请求数据中删除了“代码”和“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
}
}
几个星期以来,我一直试图得到它 运行 并且快要发疯了。希望这能拯救一些人的神经。
在 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 header 请求中使用“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
{
...
}
}
可以在下面找到刷新访问令牌的正确 http 端点
HTTP POST https://accounts.google.com/o/oauth2/token
client_id={ClientId}&client_secret={ClientSecret}&refresh_token=1/ffYmfI0sjR54Ft9oupubLzrJhD1hZS5tWQcyAvNECCA&grant_type=refresh_token
我实际上有一个将 google .net 客户端库与 Xamarin 一起使用的示例,我必须调整授权以适应它。我会四处看看是否能找到代码。
已修复。 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 从请求数据中删除了“代码”和“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
}
}
几个星期以来,我一直试图得到它 运行 并且快要发疯了。希望这能拯救一些人的神经。