Ich versuche, über die Server-Server-Methode mit der aktivierten BigQuery-API meiner App zu kommunizieren.Google OAuth2-Dienstkonto-Zugriffstokenanforderung gibt die Antwort "Ungültige Anforderung"
Ich habe alle Felder auf diesem Google guide für die Konstruktion meiner JWT so gut wie möglich in C# angekreuzt.
Und ich habe Base64Url codiert alles, was notwendig war.
jedoch die einzige Antwort, die ich von Google erhalten, ist eine 400 Bad Request
"error" : "invalid_request"
ich gemacht habe aus diesen anderen SO Fragen von allen folgenden sicher:
- 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
Ich bekomme das gleiche Ergebnis, wenn ich Fiddler verwende. Die Fehlermeldung fehlt frustrierend im Detail! Was kann ich sonst noch versuchen ?! Hier ist mein 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;
}
}
Ich finde nichts offensichtlich offensichtlich, und ich bin durch jede Zeile Ihres Codes gegangen. Eine Sache könnte sein, dass Sie den Grant-Typ in Ihrem Wörterbuch codieren, und FormUrlEncodedContent könnte es am Ende doppelt codieren. Also würde ich stattdessen "urn: ietf: params: oauth: grant-type: jwt-bearer" versuchen. –
Sieht so aus, als ob HttpClient von einer sehr aktuellen Version von .NET Framework stammt, also installiere ich das und probiere den Code auch direkt aus. Ich habe auch intern ein paar Leute angesprochen, die vielleicht helfen könnten. –