I'm using the Mirror API .NET Library with a Google Service Account to do 3rd Party Authentication via the MyGlass app. I'm following the Authentication for GDK Glassware documentation to authenticate my users server-side and then insert the account.
When I try to insert a new account using the Mirror API, I get an OAuth Error: "invalid_grant":
Stack Trace:
Google.Apis.Auth.OAuth2.Responses.TokenResponseException was unhandled by user code HResult=-2146233088 Message=Error:"invalid_grant", Description:"", Uri:"" Source=Google.Apis
at Google.Apis.Requests.ClientServiceRequest`1.Execute() in c:\code\google.com\google-api-dotnet-client\default_182\Tools\Google.Apis.Release\bin\Debug\output\default\Src\GoogleApis\Apis\Requests\ClientServiceRequest.cs:line 96\r\n
It's being unwrapped and thrown by the Execute() function in ClientServiceRequest.cs. Line 96.
Source Code:
const string password = "notasecret";
X509Certificate2 certificateToExport = new X509Certificate2(HostingEnvironment.MapPath("/Path/To/Certificate.p12"), password, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable);
var rsa = (RSACryptoServiceProvider)certificateToExport.PrivateKey;
// Have to export the provider or you get an "Invalid Algorithm" error when
// trying to sign the request.
RSACryptoServiceProvider cryptoProvider = new RSACryptoServiceProvider();
cryptoProvider.ImportParameters(rsa.ExportParameters(true));
var serviceAccountCredential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(id: "MYCLIENTID.apps.googleusercontent.com")
{
Key = cryptoProvider,
Scopes = new List<string>() { "https://www.googleapis.com/auth/glass.thirdpartyauth" },
User = "MYCLIENTID@developer.gserviceaccount.com"
});
var mirrorService = new MirrorService(new BaseClientService.Initializer() { HttpClientInitializer = serviceAccountCredential });
Account account = new Account() { AuthTokens = new AuthToken[] { new AuthToken() { AuthTokenValue = sessionKey, Type = "sessionKey" } } };
// Exception thrown here
Account insertedAccount = mirrorService.Accounts.Insert(account, userToken: userToken, accountType: "example.com", accountName: accountName).Execute();
Some things I've double and triple-checked:
- I have the correct client ID and email address.
- I have provided the scope: https://www.googleapis.com/auth/glass.thirdpartyauth.
- The userToken that was passed to me as a query parameter by the MyGlass app webview is provided back to the MirrorAPI.
- I'm signing the request with the certificate provided to me by Google.
- MyGlass is using the correct authentication redirect URL
- The Google Analytics documentation says about an "invalid_grant" error:
- Your server's clock is not in sync with NTP.
- The refresh token limit has been exceeded.
Server clock is in-sync. This happens on multiple machines. Will investigate whether/how the token limit has been exceeded. I was under the impression that the API library would handle refreshes for me.
I feel I've completely mis-understood something (likely). I'd appreciate someone pointing out what I've got wrong here.