Trying to get a basic Google Cloud Endpoints gRPC project working with an OAuth2.0 auth provider

1,033 views
Skip to first unread message

julie

unread,
Aug 24, 2017, 1:50:06 PM8/24/17
to grpc.io

Hi, I'm trying to get my Google Cloud Endpoints project with gRPC working with an OAuth2.0 authentication provider using GoogleCredentials


I followed the steps in this tutorial and could make an authenticated request by generating the jwt token and setting the audience and issuer etc

 https://cloud.google.com/endpoints/docs/using-service-to-service-authentication-grpc#make_an_authenticated_grpc_call


But we need to use GoogleCredentials for authentication and I have tried making the client request in several ways but it did not work out

Below is the relevant piece of my Client code along with my api_config_auth.yaml file


CLIENT:


public class ReporterClient {

 
public static void main(String[] args) throws Exception {

 
// Create gRPC stub.

   
ReporterGrpc.ReporterBlockingStub reporterBlockingStub = createReporterStub(host, port);

    getParams
(reporterBlockingStub, domain, type, objectName, data);

 
}

 
//  Send Request to Server

 
public static void getParams(ReporterGrpc.ReporterBlockingStub reporterBlockingStub,String domain, String type, String objectName, String data) {

   
GenerateReportRequest request =  GenerateReportRequest.newBuilder().setDomain(domain).setType(type).setObjectName(objectName).setData(data).build();

   
GenerateReportResponse response = reporterBlockingStub.generateReport(request);

 
}

// Version 1: Without scopes

 
public static ReporterGrpc.ReporterBlockingStub createReporterStub(String host, int port) throws Exception {

   
Channel channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext(true).build();

   
GoogleCredentials googleCredentials = Environment.get().computeEngineDefaultCredentials();

   
return ReporterGrpc.newBlockingStub(channel)

       
.withCallCredentials(MoreCallCredentials

           
.from(googleCredentials));

 
}

// Version 2: With scopes

 
public static ReporterGrpc.ReporterBlockingStub createReporterStubTry(String host, int port) throws Exception {

   
Channel channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext(true).build();

   
List<String> scopes = new ArrayList<>();

    scopes
.add("https://MY_SERVICE_CONFIGURATION_NAME”);

    GoogleCredentials googleCredentials = Environment.get().computeEngineDefaultCredentials().createScoped(scopes);

    return ReporterGrpc.newBlockingStub(channel)

        .withCallCredentials(MoreCallCredentials

            .from(googleCredentials));
  }

}



YAML File : API_CONFIG_AUTH.yaml:


# Reporter gRPC API configuration.

type
: google.api.Service

config_version
: 3

# Name of the service configuration.

name
: MY_SERVICE_CONFIGURATION_NAME

# API title to appear in the user interface (Google Cloud Console).

title
: Reporter gRPC API

apis
:

 
- name: reporter.Reporter

# API usage restrictions.

usage
:

  rules
:

 
# GenerateReport method can be called without an API Key.

 
- selector: reporter.Reporter.GenerateReport

    allow_unregistered_calls
: true

# Request authentication.

authentication
:

  providers
:

 
- id: google_service_account

   
# Replace SERVICE-ACCOUNT-ID with your service account's email address.

    issuer
: MY_SERVICE_ACCOUNT_ID

    jwks_uri
: https://www.googleapis.com/robot/v1/metadata/x509/MY_SERVICE_ACCOUNT_ID

  rules
:

 
# This auth rule will apply to all methods.

 
- selector: "*"

    requirements
:
     
- provider_id: google_service_account



// Error for Version 1: Without scopes


Exception in thread "main" io.grpc.StatusRuntimeException: PERMISSION_DENIED: JWT validation failed: Audience not allowed

at io.grpc.stub.ClientCalls.toStatusRuntimeException(ClientCalls.java:212)

at io.grpc.stub.ClientCalls.getUnchecked(ClientCalls.java:193)

at io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:126)

at com.soliduslink.vault.reporter.endpoints.ReporterGrpc$ReporterBlockingStub.generateReport(ReporterGrpc.java:138)

at com.soliduslink.vault.reporter.endpoints.ReporterClient.getParams(ReporterClient.java:143)

at com.soliduslink.vault.reporter.endpoints.ReporterClient.main(ReporterClient.java:118)


// Error for Version 2: With scopes


Exception in thread "main" io.grpc.StatusRuntimeException: UNAUTHENTICATED

at io.grpc.stub.ClientCalls.toStatusRuntimeException(ClientCalls.java:212)

at io.grpc.stub.ClientCalls.getUnchecked(ClientCalls.java:193)

at io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:126)

at com.soliduslink.vault.reporter.endpoints.ReporterGrpc$ReporterBlockingStub.generateReport(ReporterGrpc.java:138)

at com.soliduslink.vault.reporter.endpoints.ReporterClient.getParams(ReporterClient.java:143)

at com.soliduslink.vault.reporter.endpoints.ReporterClient.main(ReporterClient.java:118)

Caused by: java.io.IOException: Error parsing token refresh response. Expected value access_token not found.

at com.google.auth.oauth2.OAuth2Utils.validateString(OAuth2Utils.java:116)

at com.google.auth.oauth2.ServiceAccountCredentials.refreshAccessToken(ServiceAccountCredentials.java:371)

at com.google.auth.oauth2.OAuth2Credentials.refresh(OAuth2Credentials.java:149)

at com.google.auth.oauth2.OAuth2Credentials.getRequestMetadata(OAuth2Credentials.java:135)

at io.grpc.auth.GoogleAuthLibraryCallCredentials$1.run(GoogleAuthLibraryCallCredentials.java:95)

at io.grpc.stub.ClientCalls$ThreadlessExecutor.waitAndDrain(ClientCalls.java:575)

at io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:120) 

jis...@google.com

unread,
Aug 24, 2017, 3:49:33 PM8/24/17
to grpc.io

j...@soliduslink.com

unread,
Aug 24, 2017, 4:17:55 PM8/24/17
to grpc.io, jis...@google.com, Andrew Moedinger

that's really great to know to use ServiceAccountJwtAccessCredentials. but may I ask what's the major diffs between ServiceAccountJwtAccessCredentials and ServiceAccountCredentials. and in which case we should use ServiceAccountCredentials?

Thanks,
Jun

jis...@google.com

unread,
Aug 24, 2017, 4:27:31 PM8/24/17
to grpc.io, jis...@google.com, a...@soliduslink.com, j...@soliduslink.com

If you require setting the JWT as an authorization Bearer token in your request for a given audience,  ServiceAccountJwtAccessCredentials is useful.

The JWT that is created from ServiceAccountCredentials

julie

unread,
Aug 25, 2017, 9:02:37 AM8/25/17
to grpc.io, jis...@google.com, a...@soliduslink.com, j...@soliduslink.com

Thanks a lot for your comments!


Update on the issue:


We have modified our Client to use ServiceAccountJwtAccessCredentials 


public static ReporterGrpc.ReporterBlockingStub createReporterStub(String host, int port) throws Exception {

 
Channel channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext(true).build();


 
ServiceAccountJwtAccessCredentials serviceAccountJwtAccessCredentials = Environment.get().computeEngineDefaultCredentials();

 
return ReporterGrpc.newBlockingStub(channel).withCallCredentials(

         
new GoogleAuthLibraryCallCredentials(serviceAccountJwtAccessCredentials));

}



It works but with a change in the class GoogleAuthLibraryCallCredentials.java ,

https://github.com/grpc/grpc-java/blob/master/auth/src/main/java/io/grpc/auth/GoogleAuthLibraryCallCredentials.java


Currently  the audience that  is set by  ServiceAccountJwtAccessCredentials is being overwritten by the above line: ReporterGrpc.newBlockingStub(channel).withCallCredentials(new GoogleAuthLibraryCallCredentials(serviceAccountJwtAccessCredentials)) 


So instead of the audience (SERVICE_CONFIGURATION_NAME) that we set, we are obtaining a string like : https://35.195.24.28:80/reporter.Reporter

Which is being constructed by https://github.com/grpc/grpc-java/blob/master/auth/src/main/java/io/grpc/auth/GoogleAuthLibraryCallCredentials.java#L123


After we changed the uri passed to null at : https://github.com/grpc/grpc-java/blob/master/auth/src/main/java/io/grpc/auth/GoogleAuthLibraryCallCredentials.java#L98 , we were able to point to the right audience: 


Map<String, List<String>> metadata = creds.getRequestMetadata(uri) -> Map<String, List<String>> metadata = creds.getRequestMetadata(null)


Now the ServiceAccountJwtAccessCredentials picks up the right audience from this line:

https://github.com/google/google-auth-library-java/blob/master/oauth2_http/java/com/google/auth/oauth2/ServiceAccountJwtAccessCredentials.java#L253


    if (uri == null) {
       
if (defaultAudience != null) {
         uri
= defaultAudience;
       
} else {
         
……
       
}
     
}



Is this working as intended or did we miss something? We did expect the GoogleAuthLibraryCallCredentials.java to overwrite the audience we set.

We were wondering whether ServiceAccountJwtAccessCredentials class is compatible with CallCredentials class or if there is another wrapper available to pass the ServiceAccountJwtAccessCredentials.

julie

unread,
Aug 25, 2017, 9:07:16 AM8/25/17
to grpc.io, jis...@google.com, a...@soliduslink.com, j...@soliduslink.com
I meant We did NOT expect the GoogleAuthLibraryCallCredentials.java to overwrite the audience we set.

jis...@google.com

unread,
Aug 25, 2017, 5:09:06 PM8/25/17
to grpc.io, jis...@google.com, a...@soliduslink.com, j...@soliduslink.com

Have you looked at the way its done in the tests here ? 

and passing Attributes to callCredentials.applyRequestMetadata(method, attrs, executor, applier) ?

If you still see issues, I think its worth reporting here : https://github.com/grpc/grpc-java/issues

julie

unread,
Aug 30, 2017, 1:40:36 AM8/30/17
to grpc.io, jis...@google.com, a...@soliduslink.com, j...@soliduslink.com
Thanks for your reply.

Still facing the same issue. Passing the attributes to applyRequestMetadata(method, attrs, appExecutor, applier) did not work as it would be overwriting the other internally set parameters.

Will be reporting an issue for the same
Message has been deleted

j...@soliduslink.com

unread,
Aug 30, 2017, 5:42:26 AM8/30/17
to grpc.io, jis...@google.com, a...@soliduslink.com, j...@soliduslink.com
Hi Jisha,

Btw, would it be possible to have the gRPC client on AppEngine? ManagedChannelBuilder is not supported in AppEngine restricted environment. We're wondering if https://cloud.google.com/endpoints/docs/grpc/transcoding is the right way to go. something like we build a HTTP/JSON request on AppEngine to call a gRPC backend.

Thanks,
Jun

On Friday, August 25, 2017 at 11:09:06 PM UTC+2, jis...@google.com wrote:

Eric Anderson

unread,
Aug 30, 2017, 2:24:52 PM8/30/17
to jis...@google.com, grpc.io
"version 1" was already likely using JWT. gRPC's MoreCallCredentials.from() tries to convert any ServiceAccountCredentials to a ServiceAccountJwtAccessCredentials. This is possible as long as there aren't scopes set.

"version 1"'s failure of "PERMISSION_DENIED: JWT validation failed: Audience not allowed" looks like it came from the remote server. It didn't like the JWT for some reason.

"version 2"'s "Error parsing token refresh response. Expected value access_token not found." failed locally while trying to obtain an OAuth access token. It wasn't even able to send a request to the OAuth server.

Based on another part of this thread I think I see what is wrong, but I'll reply directly to that email.

--
You received this message because you are subscribed to the Google Groups "grpc.io" group.
To unsubscribe from this group and stop receiving emails from it, send an email to grpc-io+unsubscribe@googlegroups.com.
To post to this group, send email to grp...@googlegroups.com.
Visit this group at https://groups.google.com/group/grpc-io.
To view this discussion on the web visit https://groups.google.com/d/msgid/grpc-io/7d00a112-24e1-43ef-b50e-671204014601%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Eric Anderson

unread,
Aug 30, 2017, 2:30:04 PM8/30/17
to julie, grpc.io, jis...@google.com, a...@soliduslink.com, j...@soliduslink.com
On Fri, Aug 25, 2017 at 6:02 AM, julie <ju...@soliduslink.com> wrote:

So instead of the audience (SERVICE_CONFIGURATION_NAME) that we set, we are obtaining a string like : https://35.195.24.28:80/reporter.Reporter

JWT's audience is set based on the Channel's host. You need to use a hostname instead of an IP address with Channel.forAddress(). Or rather, you need to use the hostname that the server knows itself as (it does a string comparison of the audience it expects and the audience used). Since JWT is expected to be zero-configuration, it automatically computes the audience per-request.

I'll note that overrideAuthority had a bug earlier that would have caused a similar error. But that's been fixed.

j...@soliduslink.com

unread,
Aug 30, 2017, 4:57:48 PM8/30/17
to grpc.io, ju...@soliduslink.com, jis...@google.com, a...@soliduslink.com, j...@soliduslink.com
Thanks Eric!

even if we set domain name the audience would look like https://{domain_name}/reporter.Reporter. however, the ESP would expect the audience to be  "https://reporter.endpoints.{projectid}.cloud.goog". are we missing something here?

Besides the audience problem, we have a bigger issue to make a gRPC client on AppEngine. The problem is ManagedChannelBuilder is not supported on AppEngine restricted environment. Do you know if https://cloud.google.com/endpoints/docs/grpc/transcoding is the right way to go. something like we build a HTTP/JSON request on AppEngine to call a gRPC backend.

Jun

Eric Anderson

unread,
Aug 30, 2017, 5:01:56 PM8/30/17
to j...@soliduslink.com, grpc.io, jis...@google.com, a...@soliduslink.com
On Wed, Aug 30, 2017 at 2:42 AM, <j...@soliduslink.com> wrote:
Btw, would it be possible to have the gRPC client on AppEngine? ManagedChannelBuilder is not supported in AppEngine restricted environment.

GAE Java 7 should work with the OkHttp transport. However, I believe there was a regression in GAE's Conscrypt such that it is currently failing. We're looking to resolve it.

GAE Java 8 will work with Netty transport I think with netty-tcnative, starting in grpc-java 1.6 (1.6.0 is available already, but we messed up the tag so we'll make a 1.6.1; it's safe to use 1.6.0 though). We had a bug in earlier versions of grpc-java in that we were accidentally using request threads.

If you include both OkHttp and Netty and use ManagedChannelBuilder, they will chose properly among themselves (OkHttp knows it should be preferred in Java 7).

Note that hosting a gRPC server on GAE isn't supported.

Eric Anderson

unread,
Aug 30, 2017, 5:13:10 PM8/30/17
to j...@soliduslink.com, grpc.io, julie, jis...@google.com, a...@soliduslink.com, Julien Boeuf
+julien, in case he's more familiar with ESP's different JWT audience (some docs)

On Wed, Aug 30, 2017 at 1:57 PM, <j...@soliduslink.com> wrote:
even if we set domain name the audience would look like https://{domain_name}/reporter.Reporter. however, the ESP would expect the audience to be  "https://reporter.endpoints.{projectid}.cloud.goog". are we missing something here?

It sounds like ESP needs to be fixed. JWT with gRPC is "defined" to use an audience of https://{domain_name}/{service_name}.

Besides the audience problem, we have a bigger issue to make a gRPC client on AppEngine. The problem is ManagedChannelBuilder is not supported on AppEngine restricted environment. Do you know if https://cloud.google.com/endpoints/docs/grpc/transcoding is the right way to go. something like we build a HTTP/JSON request on AppEngine to call a gRPC backend.

I just responded to that part in another email.

j...@soliduslink.com

unread,
Aug 30, 2017, 5:20:43 PM8/30/17
to grpc.io, j...@soliduslink.com, jis...@google.com, a...@soliduslink.com
That's great to know 1.6 can support gRPC client on GAE!

We're using GAE Java 7. so basically we should add
<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-okhttp</artifactId>
    <version>1.6.0</version>
</dependency>

and

<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-netty</artifactId>
    <version>1.6.0</version>
</dependency>

to our dependencies to fix the ManagedChannelBuilder issue, right?

BTW, the highest version on
has 1.6.0 been released?

Jun

Eric Anderson

unread,
Aug 30, 2017, 7:27:28 PM8/30/17
to j...@soliduslink.com, grpc.io, Jisha Abubaker, Andrew Moedinger
On Wed, Aug 30, 2017 at 2:20 PM, <j...@soliduslink.com> wrote:
That's great to know 1.6 can support gRPC client on GAE!

We're using GAE Java 7. so basically we should add
<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-okhttp</artifactId>
    <version>1.6.0</version>
</dependency>

and

<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-netty</artifactId>
    <version>1.6.0</version>
</dependency>

to our dependencies to fix the ManagedChannelBuilder issue, right?

Yes, although with netty-tcnative-boringssl-static as well. And the caveat that I believe Java 7 is broken, but we're working on fixing it.

BTW, the highest version on
has 1.6.0 been released?

Yes. It's normal for it to take a day+ for Maven search indexes to be updated.


Reply all
Reply to author
Forward
0 new messages