15
votes

I'm trying to implement Google oAuth 2 for service accounts described here: https://developers.google.com/accounts/docs/OAuth2ServiceAccount on UnityScript (or C# - that doesn't matter because they both use the same Mono .NET classes).

I've found similar topic here: Is there a JSON Web Token (JWT) example in C#? web-token-jwt-example-in-c but I still don't have a success.

Fist of all, I have generated header and claimset (that are just like in google documentation)

var header: String = GetJWTHeader();
var claimset: String = GetJWTClaimSet();

The result is (separated with new lines for clarity):

{"alg":"RS256","typ":"JWT"}

{"iss":"425466719070-1dg2rebp0a8fn9l02k9ntr6u5o4a8lp2.apps.googleusercontent.com",

"scope":"https://www.googleapis.com/auth/prediction",

"aud":"https://accounts.google.com/o/oauth2/token",

"exp":1340222315,

"iat":1340218715}

Base-64 encoding methods:

public static function Base64Encode(b: byte[]): String {
    var s: String = Convert.ToBase64String(b);
    s = s.Replace("+", "-");
    s = s.Replace("/", "_");
    s = s.Split("="[0])[0]; // Remove any trailing '='s
    return s;
}

public static function Base64Encode(s: String): String {    
    return Base64Encode(Encoding.UTF8.GetBytes(s));
}

Then I'm making a signature.

var to_sign: byte[] = 
     Encoding.UTF8.GetBytes(Base64Encode(header) + "." + Base64Encode(claimset));
var cert: X509Certificate2 = 
     new X509Certificate2(google_pvt_key.ToArray(), "notasecret");
var rsa: RSACryptoServiceProvider = cert.PrivateKey;
var sgn: String = Base64Encode(rsa.SignData(to_sign, "SHA256"));

var jwt: String = Base64Encode(header) + "." + Base64Encode(claimset) + 
                     "." + sgn;

And then forming the request:

var url: String = "https://accounts.google.com/o/oauth2/token";
var form: WWWForm = new WWWForm();
form.AddField("grant_type", "assertion");
form.AddField("assertion_type", "http://oauth.net/grant_type/jwt/1.0/bearer");
form.AddField("assertion", jwt);
var headers: Hashtable = form.headers;
headers["Content-Type"] = "application/x-www-form-urlencoded";

var www: WWW = new WWW(url, form.data, headers);

And all I get is "Error 400: Bad request".

The encoded data looks like (line breaks added for clarity):

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.

eyJpc3MiOiI0MjU0NjY3MTkwNzAtMWRnMnJlYnAwYThmbjlsMDJrOW50cjZ1NW80YThscDIuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTM0MDIyMjMxNSwiaWF0IjoxMzQwMjE4NzE1fQ.

lIFg7-Og_BcC5qpICLt7USwGIHUOz-vV4ADNq0AWhuRtsvFrbZn5mxk4n9r5qU66q4reTVVAtuW06DeGsdcBMNgEdIMvN6VuYQybs64p9mqrfECBYxO1FWHbUG-2On1IpowybEsRRUjZfp0jFuEY7SLE3XRaXan0k5zmejcvLQo

I've spent two days trying to figure out what is wrong but I can't see.

Also, I couldn't find any suitable documentation and examples.

I'm trying just to recieve a token.

  1. Am I signing the bytes the right way?
  2. What should "scope" parameter in claimset look like? I've tried "https://www.googleapis.com/auth/devstorage.readonly" and "https://www.googleapis.com/auth/prediction".
  3. What "iss" parameter should be equal to? Client-id or e-mail address? (tried both)
  4. What are the ways to find out my mistake?
  5. Are there any C# libraries for Service Application (not for installed apps or client login)?

I'm getting crazy... It has to work, but it doesn't... :-/

2
I'm having a tough time too implementing service account authentication in c#! Can you confirm for me that you successfully used the grant_type and assertion_type fields as they are shown in your example? thanksNick

2 Answers

8
votes

The solution was that in request code all slashes have to be backslashed

WRONG:

"scope":"https://www.googleapis.com/auth/prediction",
"aud":"https://accounts.google.com/o/oauth2/token",

CORRECT:

"scope":"https:\\/\\/www.googleapis.com\\/auth\\/prediction",
"aud":"https:\\/\\/accounts.google.com\\/o\\/oauth2\\/token",
-1
votes

Try to use system.identitymodel.tokens.jwt .Net library You can install it from NuGet. See example in my post here (I used it to authenticate websockets server, but JWT handling is generic)

http://mydevtricks.blogspot.co.il/2014/10/xsocketsnet-authentication-with-jwt.html