问题描述
我想用我的应用程序的通信通过服务器启用BigQuery的API服务器的方法。
我已经打勾这个所有的箱子为构建我的智威汤逊,尽我所能在C#
和我有那个必要Base64Url EN codeD的一切。
不过,我从谷歌得到的唯一回应是400错误的请求
错误:INVALID_REQUEST
我已经从所有这些做题下面的确信:
- 适当加密
- 权利要求中的所有反斜线
我得到相同的结果时,我使用Fiddler。该错误消息是令人沮丧的缺乏细节!我还可以尝试?这里是我的code:
类节目
{
静态无效的主要(字串[] args)
{
// 证书
VAR证书=新X509Certificate2(@<路径到我的证书>的.p12,notasecret); //头
VAR头= {新典型值=智威汤逊,ALG =RS256}; // claimset
变种次= GetExpiryAndIssueDate();
VAR claimset =新
{
ISS =<我的应用程序和GT的客户端ID的电子邮件地址;,
范围=https://www.googleapis.com/auth/bigquery
AUD =https://accounts.google.com/o/oauth2/token
IAT =倍[0]
EXP =倍[1],
}; // EN codeD头
VAR headerSerialized = JsonConvert.SerializeObject(头);
VAR headerBytes = Encoding.UTF8.GetBytes(headerSerialized);
VAR headerEn codeD = Base64UrlEn code(headerBytes); // EN codeD claimset
VAR claimsetSerialized = JsonConvert.SerializeObject(claimset);
VAR claimsetBytes = Encoding.UTF8.GetBytes(claimsetSerialized);
VAR claimsetEn codeD = Base64UrlEn code(claimsetBytes); //输入
VAR输入= headerEn codeD +。 + claimsetEn codeD;
变种inputBytes = Encoding.UTF8.GetBytes(输入); // signiture
VAR RSA = certificate.PrivateKey为的RSACryptoServiceProvider;
VAR cspParam =新CspParameters
{
KeyContainerName = rsa.CspKeyContainerInfo.KeyContainerName,
KeyNumber = rsa.CspKeyContainerInfo.KeyNumber == KeyNumber.Exchange? 1:2
};
VAR aescsp =新的RSACryptoServiceProvider(cspParam){PersistKeyInCsp = FALSE};
变种signatureBytes = aescsp.SignData(inputBytesSHA256);
VAR signatureEn codeD = Base64UrlEn code(signatureBytes); //智威汤逊
VAR JWT = headerEn codeD +。 + claimsetEn codeD +。 + signatureEn codeD; Console.WriteLine(JWT); VAR的客户=新的HttpClient();
VAR URI =https://accounts.google.com/o/oauth2/token;
无功后=新词典<字符串,字符串>
{
{断言,智威汤逊},
{grant_type,瓮%3Aietf%3Aparams%3Aoauth%3Agrant型%3Ajwt旗手}
};
VAR内容=新FormUrlEn codedContent(岗位);
VAR的结果= client.PostAsync(URI,内容)。结果; Console.WriteLine(结果);
Console.WriteLine(result.Content.ReadAsStringAsync()的结果。);
到Console.ReadLine();
} 私有静态诠释[] GetExpiryAndIssueDate()
{
变种utc0 =新日期时间(1970年,1,1,0,0,0,0,DateTimeKind.Utc);
VAR issueTime = DateTime.Now; VAR IAT =(int)的issueTime.Subtract(utc0).TotalSeconds;
VAR EXP =(int)的issueTime.AddMinutes(55).Subtract(utc0).TotalSeconds; 返回新的[] {IAT,EXP};
} 私人静态字符串Base64UrlEn code(字节[]输入)
{
无功输出= Convert.ToBase64String(输入);
输出= output.Split('=')[0]; //删除任何尾随'=的
输出= output.Replace(+, - ); //编码字符第62
输出= output.Replace('/','_'); //编码字符第63
返回输出;
}
}
看起来像我在评论上述猜测是正确的。我改变了你的code工作:
骨灰盒%3Aietf%3Aparams%3Aoauth%3Agrant型%3Ajwt旗手
到
金塔:IETF:params:一个OAuth的:授型:智威汤逊的旗手
看起来你是不小心双重编码它。
我现在得到它看起来像一个响应:
{
ACCESS_TOKEN:1 / _5pUwJZs9a545HSeXXXXXuNGITp1XtHhZXXxxyyaacqkbc
token_type:旗手,
expires_in:3600
}
编辑注:请确保您的服务器上正确的日期/时间/时区/ DST配置。通过甚至几秒钟具有时钟关闭将导致 invalid_grant
错误。 将给来自美国官立官方计时,包括UTC。
I'm trying to communicate with my app's enabled BigQuery API via the server to server method.
I've ticked all the boxes on this Google guide for constructing my JWT as best I can in C#.
And I've Base64Url encoded everything that was necessary.
However, the only response I get from google is a 400 Bad Request
"error" : "invalid_request"
I've made sure of all of the following from these other SO questions:
- The signature is properly encrypted using RSA and SHA256
- I am using POST and using application/x-www-form-urlencoded content type
- Escaped all the backslashes in the claim set
- Tried various grant_type and assertion values in the POST data
I get the same result when I use Fiddler. The error message is frustratingly lacking in detail! What else can I try?! Here's my code:
class Program
{
static void Main(string[] args)
{
// certificate
var certificate = new X509Certificate2(@"<Path to my certificate>.p12", "notasecret");
// header
var header = new { typ = "JWT", alg = "RS256" };
// claimset
var times = GetExpiryAndIssueDate();
var claimset = new
{
iss = "<email address of the client id of my app>",
scope = "https://www.googleapis.com/auth/bigquery",
aud = "https://accounts.google.com/o/oauth2/token",
iat = times[0],
exp = times[1],
};
// encoded header
var headerSerialized = JsonConvert.SerializeObject(header);
var headerBytes = Encoding.UTF8.GetBytes(headerSerialized);
var headerEncoded = Base64UrlEncode(headerBytes);
// encoded claimset
var claimsetSerialized = JsonConvert.SerializeObject(claimset);
var claimsetBytes = Encoding.UTF8.GetBytes(claimsetSerialized);
var claimsetEncoded = Base64UrlEncode(claimsetBytes);
// input
var input = headerEncoded + "." + claimsetEncoded;
var inputBytes = Encoding.UTF8.GetBytes(input);
// signiture
var rsa = certificate.PrivateKey as RSACryptoServiceProvider;
var cspParam = new CspParameters
{
KeyContainerName = rsa.CspKeyContainerInfo.KeyContainerName,
KeyNumber = rsa.CspKeyContainerInfo.KeyNumber == KeyNumber.Exchange ? 1 : 2
};
var aescsp = new RSACryptoServiceProvider(cspParam) { PersistKeyInCsp = false };
var signatureBytes = aescsp.SignData(inputBytes, "SHA256");
var signatureEncoded = Base64UrlEncode(signatureBytes);
// jwt
var jwt = headerEncoded + "." + claimsetEncoded + "." + signatureEncoded;
Console.WriteLine(jwt);
var client = new HttpClient();
var uri = "https://accounts.google.com/o/oauth2/token";
var post = new Dictionary<string, string>
{
{"assertion", jwt},
{"grant_type", "urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer"}
};
var content = new FormUrlEncodedContent(post);
var result = client.PostAsync(uri, content).Result;
Console.WriteLine(result);
Console.WriteLine(result.Content.ReadAsStringAsync().Result);
Console.ReadLine();
}
private static int[] GetExpiryAndIssueDate()
{
var utc0 = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
var issueTime = DateTime.Now;
var iat = (int)issueTime.Subtract(utc0).TotalSeconds;
var exp = (int)issueTime.AddMinutes(55).Subtract(utc0).TotalSeconds;
return new[]{iat, exp};
}
private static string Base64UrlEncode(byte[] input)
{
var output = Convert.ToBase64String(input);
output = output.Split('=')[0]; // Remove any trailing '='s
output = output.Replace('+', '-'); // 62nd char of encoding
output = output.Replace('/', '_'); // 63rd char of encoding
return output;
}
}
Looks like my guess in the comment above was correct. I got your code working by changing:
"urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer"
to:
"urn:ietf:params:oauth:grant-type:jwt-bearer"
Looks like you were accidentally double-encoding it.
I now get a response which looks something like:
{
"access_token" : "1/_5pUwJZs9a545HSeXXXXXuNGITp1XtHhZXXxxyyaacqkbc",
"token_type" : "Bearer",
"expires_in" : 3600
}
Edited Note: please make sure to have the correct date/time/timezone/dst configuration on your server. Having the clock off by even a few seconds will result in an invalid_grant
error. http://www.time.gov will give the official time from the US govt, including in UTC.
这篇关于谷歌的OAuth2服务帐户访问令牌请求给予“无效请求的回应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!