1

Followed

OAuth example

successfully getting bearer token, but response is:

{StatusCode: 401, ReasonPhrase: 'Unauthorized', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
  Vary: X-Origin
  Vary: Referer
  Vary: Origin
  Vary: Accept-Encoding
  X-XSS-Protection: 1; mode=block
  X-Frame-Options: SAMEORIGIN
  X-Content-Type-Options: nosniff
  Alt-Svc: hq=":443"; ma=2592000; quic=51303433; quic=51303432; quic=51303431; quic=51303339; quic=51303335,quic=":443"; ma=2592000; v="43,42,41,39,35"
  Transfer-Encoding: chunked
  Accept-Ranges: none
  Cache-Control: private
  Date: Thu, 03 May 2018 13:29:53 GMT
  Server: ESF
  WWW-Authenticate: Bearer realm="https://accounts.google.com/"
  Content-Type: application/json; charset=UTF-8
}}

using a service account with 'ML Engine Developer' Role. Here is the code:

        var url = $"{googleapiprojecturl}/models/{modelname}/versions/{version}:predict";
        GoogleCredential credential;
        using (Stream stream = new FileStream(@"C:\serviceacctkey.json", FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            credential = GoogleCredential.FromStream(stream);
        }
        var bearer_token = await credential.UnderlyingCredential.GetAccessTokenForRequestAsync(url);
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearer_token);
        var content = new StringContent(payloadJsonString, Encoding.UTF8, "application/json");
        var responseMessage = await client.PostAsync(url, content);
        responseMessage.EnsureSuccessStatusCode();

where googleapiprojecturl = https://ml.googleapis.com/v1/projects/{projectID}

  • What IAM permissions does that service account have? – rhaertel80 May 03 '18 at 14:42
  • Has 'ML Engine Developer', just added 'Service Account Token Creator', no change.. the token was and is being generated. – Jason Sackett May 03 '18 at 15:19
  • Added 'Project Editor' also, no change. – Jason Sackett May 03 '18 at 15:22
  • I can't look at this in detail right now, but it's possible you need to add the correct scopes to the service credential. I.e. `credential = GoogleCredential.FromStream(stream).CreateScoped(...);` – Chris May 03 '18 at 16:35
  • Note also that you can probably use this package: https://www.nuget.org/packages/Google.Apis.CloudMachineLearningEngine.v1/ rather than calling the JSON/REST enpoint directly. – Chris May 03 '18 at 16:40

2 Answers2

4

as Chris suggested above, as comment on the question, the answer was scope on the credential before asking for token:

credential = GoogleCredential.FromStream(stream).CreateScoped(new[] { CloudMachineLearningEngineService.Scope.CloudPlatform });
0

I haven't done this in C#, but I also had trouble in Python with the following similar code:

# Doesn't work
# creds = GoogleCredentials.from_stream(SERVICE_ACCOUNT_FILE)

In Python, the following worked instead:

from oauth2client import service_account
creds = service_account.ServiceAccountCredentials.from_json_keyfile_name('key.json', SCOPES)
creds.get_access_token()

In C#, it looks like you would use the ServiceAccountCredentials class.

rhaertel80
  • 8,254
  • 1
  • 31
  • 47
  • Made the changes you suggested (same result) like this: ServiceAccountCredential credential; using (Stream stream = new FileStream(@"C:\serviceacctkey.json", FileMode.Open, FileAccess.Read, FileShare.Read)) { credential = ServiceAccountCredential.FromServiceAccountData(stream); } var bearer_token = await credential.GetAccessTokenForRequestAsync(url); – Jason Sackett May 03 '18 at 15:15
  • I'll try to dig into this, but it may take a few days. Can you confirm that you are able to send requests from gcloud? Are you willing to try Python simply for validation? – rhaertel80 May 03 '18 at 17:03
  • Yes, this model/version works from curl, gcloud, etc. – Jason Sackett May 03 '18 at 17:23