Created
November 30, 2018 16:35
-
-
Save DomDumont/51f40e5d8a85f86fad84b0a06f11e05e to your computer and use it in GitHub Desktop.
Google json web token for Unity
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Text; | |
using System.Security.Cryptography; | |
using System.Security.Cryptography.X509Certificates; | |
using System.Collections.Generic; | |
using UnityEngine; | |
public class GoogleJsonWebToken | |
{ | |
public const string SCOPE_READONLY = | |
"https://www.googleapis.com/auth/devstorage.read_only"; | |
public const string SCOPE_OAUTH = | |
"https://www.googleapis.com/auth/cloud-platform"; | |
public static string GetJwt( | |
string clientIdEMail, | |
string keyFilePath, | |
string scope) | |
{ | |
// certificate | |
var certificate = new X509Certificate2(keyFilePath, "notasecret"); | |
// header | |
var header = new { typ = "JWT", alg = "RS256" }; | |
// claimset | |
var times = GetExpiryAndIssueDate(); | |
var claimset = new | |
{ | |
iss = clientIdEMail, | |
scope = scope, | |
aud = "https://www.googleapis.com/oauth2/v4/token", | |
iat = times[0], | |
exp = times[1], | |
}; | |
// encoded header | |
// var headerSerialized = JsonConvert.SerializeObject(header); | |
//var headerBytes = Encoding.UTF8.GetBytes(headerSerialized); | |
JSONObject jHeader = new JSONObject(JSONObject.Type.OBJECT); | |
jHeader.AddField("typ", header.typ); | |
jHeader.AddField("alg", header.alg); | |
var headerBytes = Encoding.UTF8.GetBytes(jHeader.ToString()); | |
var headerEncoded = Base64UrlEncode(headerBytes); | |
// encoded claimset | |
//var claimsetSerialized = JsonConvert.SerializeObject(claimset); | |
//var claimsetBytes = Encoding.UTF8.GetBytes(claimsetSerialized); | |
JSONObject jClaimset = new JSONObject(JSONObject.Type.OBJECT); | |
jClaimset.AddField("iss", claimset.iss); | |
jClaimset.AddField("scope", claimset.scope); | |
jClaimset.AddField("aud", claimset.aud); | |
jClaimset.AddField("iat", claimset.iat); | |
jClaimset.AddField("exp", claimset.exp); | |
var claimsetBytes = Encoding.UTF8.GetBytes(jClaimset.ToString()); | |
var claimsetEncoded = Base64UrlEncode(claimsetBytes); | |
// input | |
var input = headerEncoded + "." + claimsetEncoded; | |
var inputBytes = Encoding.UTF8.GetBytes(input); | |
// signature | |
RSACryptoServiceProvider rsa = | |
(RSACryptoServiceProvider)certificate.PrivateKey; | |
var signatureBytes = rsa.SignData(inputBytes, "SHA256"); | |
var signatureEncoded = Base64UrlEncode(signatureBytes); | |
// jwt | |
var jwt = headerEncoded + "." + claimsetEncoded + "." + signatureEncoded; | |
return jwt; | |
} | |
public static WWW GetAccessTokenRequest(string jwt) | |
{ | |
string url = "https://www.googleapis.com/oauth2/v4/token"; | |
WWWForm form = new WWWForm(); | |
form.AddField( | |
"grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer"); | |
form.AddField("assertion", jwt); | |
Dictionary<string, string> headers = form.headers; | |
headers["Content-Type"] = "application/x-www-form-urlencoded"; | |
WWW www = new WWW(url, form.data, headers); | |
return www; | |
} | |
// from JWT spec | |
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; | |
} | |
// from JWT spec | |
private static byte[] Base64UrlDecode(string input) | |
{ | |
var output = input; | |
output = output.Replace('-', '+'); // 62nd char of encoding | |
output = output.Replace('_', '/'); // 63rd char of encoding | |
switch (output.Length % 4) // Pad with trailing '='s | |
{ | |
case 0: | |
break; // No pad chars in this case | |
case 2: | |
output += "=="; | |
break; // Two pad chars | |
case 3: | |
output += "="; | |
break; // One pad char | |
default: | |
throw new System.Exception("Illegal base64url string!"); | |
} | |
var converted = Convert.FromBase64String(output); // Standard base64 decoder | |
return converted; | |
} | |
private static int[] GetExpiryAndIssueDate() | |
{ | |
var utc0 = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); | |
var issueTime = DateTime.UtcNow; | |
var iat = (int)issueTime.Subtract(utc0).TotalSeconds; | |
var exp = (int)issueTime.AddMinutes(55).Subtract(utc0).TotalSeconds; | |
return new[] { iat, exp }; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment