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:
- 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.
From the chat thread, the issue was due to the Service Account authentication failing due to the wrong data being passed in the ServiceAccountCredential
class.
The code snippet used in the original question should be fixed with:
var serviceAccountCredential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(id: "MYCLIENTID@developer.gserviceaccount.com")
{
Key = cryptoProvider,
Scopes = new List<string>() { "https://www.googleapis.com/auth/glass.thirdpartyauth" }
});