gRPC authenticated channel using custom access token

3,630 views
Skip to first unread message

psae...@gmail.com

unread,
May 23, 2017, 10:02:24 AM5/23/17
to grpc.io


Hi all,


I'm using latest version of gRPC and I'm using node.js to make an authenticated channel using custom access token and ssl certificate


Brief explanation:

I was trying to make authenticated channel using combined credentials (ie. ssl_creds & call_creds) as shown in http://www.grpc.io/docs/guides/auth.html#authenticate-with-google-4.
But instead of using google auth, I was trying to use my own access token.


I am getting errors such as
W20170523-10:25:15.721(-3)? (STDERR) plainSignature.push( signature[key].name );
W20170523-10:25:15.720(-3)? (STDERR) ^
W20170523-10:25:15.728(-3)? (STDERR) TypeError: Cannot read property 'name' of null
W20170523-10:25:15.733(-3)? (STDERR) at __ (C:\Users\prasanna.elangovan\Desktop\Meteor_Practice\node_modules\arguejs\argue.js:117:46)


Can anyone please provide example code to achieve a authenticated channel using ssl certificate & custom access token


FYI - There is a way to do this in python  - http://www.grpc.io/grpc/python/_modules/grpc.html#access_token_call_credentials. I want to do the same in node.js.


Thanks in advance.

Michael Lumish

unread,
May 23, 2017, 1:05:13 PM5/23/17
to psae...@gmail.com, grpc.io
From that error output, I suspect that you called a method on a client object with incorrect arguments. What is the code that resulted in that error?

You should also keep in mind that the specific function grpc.credentials.createFromGoogleCredential should only be used with credentials objects returned by google-auth-library. For your own authentication, you should instead use grpc.credentials.createFromMetadataGenerator. The best documentation for that function is currently in the code, here: https://github.com/grpc/grpc/blob/master/src/node/src/credentials.js#L89.

--
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+u...@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/136526ce-dc63-4faa-986b-0568764ab0a4%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

psae...@gmail.com

unread,
May 23, 2017, 2:07:58 PM5/23/17
to grpc.io, psae...@gmail.com

Thanks Mr. Michael Lumish for your timely reply.

Actually I think that error is because I was calling server-side streaming function as simple rpc function. So please ignore the previous error.
But when I tried to call correctly I got the below error. I guess below error is caused because I'm not passing the correct parameters to grpc.credentials.createFromMetadataGenerator function  

W20170523-13:20:15.298(-3)? (STDERR) C:\Users\xxxxxxxx\Desktop\Meteor_Practice\node_modules\grpc\src\node\src\credentials.js:100
W20170523-13:20:15.300(-3)? (STDERR)     metadata_generator({service_url: service_url}, function(error, metadata) {
W20170523-13:20:15.301(-3)? (STDERR)     ^
W20170523-13:20:15.311(-3)? (STDERR) TypeError: metadata_generator is not a function
W20170523-13:20:15.317(-3)? (STDERR)     at C:\Users\xxxxxx\Desktop\Meteor_Practice\node_modules\grpc\src\node\src\credentials.js:100:5
=> Exited with code: 1


Below given is my program. I just wanted to know what is the input parameter for 
grpc.credentials.createFromMetadataGenerator function. Whether the parameter is metadata or access token?
Can you please explain me how to process the access token before passing it to grpc.credentials.createFromMetadataGenerator function.

var metadata = new grpc.Metadata();
metadata.add('authorization', access_token);
console.log(metadata);
var auth_creds = grpc.credentials.createFromMetadataGenerator(metadata);
console.log(auth_creds);
var combined_creds = grpc.credentials.combineChannelCredentials(ssl_creds, auth_creds);
var clientnew = new proto.Gateway('localhost:50001',combined_creds);
var cmd = {};
var call = clientnew.somefunction(cmd);
call.on('data', function(systems) {
  console.log(systems);
});


Michael Lumish

unread,
May 23, 2017, 2:15:02 PM5/23/17
to psae...@gmail.com, grpc.io
The createFromMetadataGenerator function takes as its argument a function. The first argument to that function is an object, which currently just contains the key "service_url", which is probably not relevant to your use case. The second argument to that function is a callback, which has the standard arguments: the first is the error, and the second is the result. Based on that code, your metadata generator should look like this

function generateMetadata(params, callback) {
  var metadata = new grpc.Metadata();
  metadata.add('authorization', access_token);
  callback(null, metadata);
}

Or, if you know the authorization header won't change, you can simply do this instead:

var metadata = new grpc.Metadata();
metadata.add('authorization', access_token);
function generateMetadata(params, callback) {
  callback(null, metadata);
}

--
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+u...@googlegroups.com.
To post to this group, send email to grp...@googlegroups.com.
Visit this group at https://groups.google.com/group/grpc-io.

psae...@gmail.com

unread,
May 23, 2017, 2:25:56 PM5/23/17
to grpc.io, psae...@gmail.com
function generateMetadata(params, callback) {
   var metadata = new grpc.Metadata();
   metadata.add('authorization', response.access_token);
   console.log(metadata);
   callback(null,metadata);
}
var auth_creds = grpc.credentials.createFromMetadataGenerator(generateMetadata);
console.log(auth_creds);
var combined_creds = grpc.credentials.combineChannelCredentials(ssl_creds, auth_creds);
var clientnew = new proto.Gateway('localhost:50001',combined_creds);
var cmd = {};
var call = clientnew.listAcousticSystems(cmd);
call.on('data', function(systems) {
   console.log(systems);
});

I tried to do as suggested. I also remember that I've tried do like this before as well. But unfortunately I was getting error in events.js and client.js in node modules (which cannot be found in mentioned url). Below I've attached the error which I got during the above method.

I20170523-15:18:27.515(-3)? CallCredentials {}
I20170523-15:18:27.532(-3)? Metadata {
I20170523-15:18:27.534(-3)?   _internal_repr: { authorization: [ 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ2ZW1jby5pbyIsImF1ZCI6InZlbWNvLmlvIiwic3ViIjoiMTFkZWVmMDUtOWUzNy00ZDQxLWJmNjgtZTE0MTQwY2IxODJmIiwiaWF0IjoxNDk1NTYzNTA3LCJleHAiOjE0OTU1NjQ0MDcsInVzZXJfbmFtZSI6InVzZXIxIn0.nLOa2c1PWWL59AIaiZjpzT_p0wSeUIoOsxsUHarTWCE' ] } }
W20170523-15:18:27.574(-3)? (STDERR) events.js:141
W20170523-15:18:27.575(-3)? (STDERR)       throw er; // Unhandled 'error' event
W20170523-15:18:27.582(-3)? (STDERR)       ^
W20170523-15:18:27.583(-3)? (STDERR)
W20170523-15:18:27.589(-3)? (STDERR) Error: Invalid Authorization Token
W20170523-15:18:27.590(-3)? (STDERR)     at ClientReadableStream._emitStatusIfDone (C:\Users\prasanna.elangovan\Desktop\Meteor_Practice\node_modules\grpc\src\node\src\client.js:201:19)
W20170523-15:18:27.598(-3)? (STDERR)     at ClientReadableStream._receiveStatus (C:\Users\prasanna.elangovan\Desktop\Meteor_Practice\node_modules\grpc\src\node\src\client.js:180:8)
W20170523-15:18:27.600(-3)? (STDERR)     at C:\Users\prasanna.elangovan\Desktop\Meteor_Practice\node_modules\grpc\src\node\src\client.js:592:14
=> Exited with code: 1

I'm also wondering that auth_creds printed before metadata

Thanks for helping me on this. 

Michael Lumish

unread,
May 23, 2017, 2:36:18 PM5/23/17
to psae...@gmail.com, grpc.io
You got an error that says "Invalid Authorization Token". That error was thrown by the call's "error" event handler, which means that that the call ended with that error. That error message probably came from the server. So, there is some problem with your access_token.

--
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+u...@googlegroups.com.
To post to this group, send email to grp...@googlegroups.com.
Visit this group at https://groups.google.com/group/grpc-io.
Message has been deleted

psae...@gmail.com

unread,
May 23, 2017, 2:39:34 PM5/23/17
to grpc.io, psae...@gmail.com
I just now noticed the error on the server side. Below error is found on the python server side

ERROR:root:Exception iterating responses: Invalid token type. Token must be a <class 'bytes'>
Traceback (most recent call last):
  File "C:\Users\prasanna.elangovan\AppData\Local\Programs\Python\Python36-32\lib\site-packages\grpc\_server.py", line 388, in _take_response_from_response_iterator
    return next(response_iterator), True
  File "C:\Users\prasanna.elangovan\Documents\io\src\test\gateway\main.py", line 124, in ListAcousticSystems
    user_uuid = extract_user_uuid_from_context(context)
  File "C:\Users\prasanna.elangovan\Documents\io\src\test\gateway\main.py", line 57, in extract_user_uuid_from_context
    valid_token = extract_access_token_from_context(context)
  File "C:\Users\prasanna.elangovan\Documents\io\src\test\gateway\main.py", line 52, in extract_access_token_from_context
    return decode_access_token(bearer_token)
  File "C:\Users\prasanna.elangovan\Documents\io\src\test\gateway\main.py", line 40, in decode_access_token
    leeway=datetime.timedelta(seconds=10)
  File "C:\Users\prasanna.elangovan\AppData\Local\Programs\Python\Python36-32\lib\site-packages\jwt\api_jwt.py", line 61, in decode
    payload, signing_input, header, signature = self._load(jwt)
  File "C:\Users\prasanna.elangovan\AppData\Local\Programs\Python\Python36-32\lib\site-packages\jwt\api_jws.py", line 150, in _load
    binary_type))
jwt.exceptions.DecodeError: Invalid token type. Token must be a <class 'bytes'>


psae...@gmail.com

unread,
May 23, 2017, 3:01:04 PM5/23/17
to grpc.io, psae...@gmail.com


Thanks Michael Lumish. Can you please confirm whether the below code is correct. I am worried whether there is some asynchronous problem. How to use auth_creds for the next function - grpc.credentials.combineChannelCredentials(ssl_creds, auth_creds) ?

function generateMetadata(params, callback) {
   var metadata = new grpc.Metadata();
   metadata.add('authorization', response.access_token);
   console.log(metadata); // Prints second
   callback(null,metadata);
}

var auth_creds = grpc.credentials.createFromMetadataGenerator(generateMetadata);
console.log(auth_creds); // Prints first
var combined_creds = grpc.credentials.combineChannelCredentials(ssl_creds, auth_creds);
var clientnew = new proto.Gateway('localhost:50001',combined_creds);
var cmd = {};
var call = clientnew.listAcousticSystems(cmd);
call.on('data', function(systems) {
   console.log(systems);
});

Michael Lumish

unread,
May 23, 2017, 3:27:44 PM5/23/17
to psae...@gmail.com, grpc.io
The auth_creds prints before the metadata because the callback is called each time you initiate a request, and it is not called immediately.

--
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+u...@googlegroups.com.
To post to this group, send email to grp...@googlegroups.com.
Visit this group at https://groups.google.com/group/grpc-io.

psae...@gmail.com

unread,
May 23, 2017, 3:31:52 PM5/23/17
to grpc.io, psae...@gmail.com
I understand it now Mr.Michael. Thanks for all your help. I made the program working by changing the metadata as follows

metadata.add('authorization', response.access_token);
// I changed the above line as follows
metadata.add('authorization', 'Bearer '+response.access_token);


Thanks for all your help. I appreciate it.
Reply all
Reply to author
Forward
0 new messages