3

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:
  1. Your server's clock is not in sync with NTP.
  2. 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.

PabloC
  • 404
  • 2
  • 13
  • 1
    If this question requires further clarification, please let me know. – PabloC Aug 21 '14 at 14:22
  • 1
    You do understand that a service account is its own entity, which means even if you could use a service account with the mirror api you would only manage to write to the service accounts glass timeline. I don't think that the service account owns a pair of glass. What exactly is it you are trying to do? – Linda Lawton - DaImTo Aug 22 '14 at 12:06
  • The account command lets you insert a new Account into the Account Manager on Glass. You are logging in using a Service account. What is it you are trying to do exactly. More information needed. – Linda Lawton - DaImTo Aug 25 '14 at 09:01
  • 1
    Thanks DalmTo. I'm trying to insert an account into the mirror api so that I can retrieve the account on the set of glasses that authenticated when the app was installed in MyGlass. I'm following Google's documentation on this, which specifically says you should use a service account to do this. Granted the documentation could be wrong, but they've referred to it themselves throughout the approval process, so I'm pretty sure it's correct. – PabloC Aug 25 '14 at 09:09
  • where is this documentation, you speak of? I use Oauth2 for mine, I cant understand how they would think a service account would work. but this may just be something I haven't heard of. – Linda Lawton - DaImTo Aug 25 '14 at 09:12
  • Linked at the top of the question: https://developers.google.com/glass/develop/gdk/authentication – PabloC Aug 25 '14 at 09:14
  • that's your probably that's only for applications installed on glass. You cant install a .net application on to glass only android. – Linda Lawton - DaImTo Aug 25 '14 at 09:17
  • 1
    No it's specifically for running on server side apps. That's why it's a service account and not a client account. – PabloC Aug 25 '14 at 10:05
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/59926/discussion-between-daimto-and-pabloc). – Linda Lawton - DaImTo Aug 25 '14 at 10:18
  • @PabloC, could you add more information in the chat? – Alain Aug 27 '14 at 17:33
  • @Alain I've updated the chat with a link to the logs you requested. Looks like you were right, the token appears to be invalid. – PabloC Sep 02 '14 at 10:02

2 Answers2

1

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" }
});
Community
  • 1
  • 1
Alain
  • 6,044
  • 21
  • 27
0

Make sure that you've submitted your Glassware at https://developers.google.com/glass/distribute/form. Be sure to mention that you're wanting to add accounts as well, and give them the account type for your application. I recall having to do this on my application before I was able to add accounts. You'd think this would be in their documentation, but I don't believe it is.

Jessie A. Morris
  • 2,267
  • 21
  • 23
  • Thanks Jessie. I've given google this information as part of getting the glassware listed store. They know I'm trying to do 3rd party auth. – PabloC Aug 29 '14 at 17:02
  • Well, that's all I've got. I seem to recall having this same issue in Python, but I think mine was due to Python not liking the key format. My Python looks almost identical to you C#/.net code. – Jessie A. Morris Aug 29 '14 at 17:17
  • I appreciate it Jessie. You know I might have to try using a different language, maybe the JS library. – PabloC Aug 30 '14 at 13:35