Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add server interceptors #419

Closed
anjmao opened this issue Jun 26, 2018 · 28 comments · Fixed by #2650
Closed

Add server interceptors #419

anjmao opened this issue Jun 26, 2018 · 28 comments · Fixed by #2650

Comments

@anjmao
Copy link

anjmao commented Jun 26, 2018

Hi,
I'm using grpc-node native package for building backend API. I noticed that there is not server interceptors (correct me if I'm wrong). I want to write server interceptors for logging, auth and so on. Without it grpc-node is pretty match useless for production. Could you share what is the status on this feature, because I'm thinking to implement it in my fork branch. Thanks.

@nicolasnoble
Copy link
Member

Server interceptors aren't in our roadmap at the moment.

@anjmao
Copy link
Author

anjmao commented Jul 1, 2018

@nicolasnoble Thanks for response. Would you accept PR if I implement them, since I need server interceptors any way to be able to use grpc for production. I saw that there is also no native C++ server interceptors, but I'm looking to implement them in js side.

@nicolasnoble
Copy link
Member

We would require this to go through a GRFC process in order to discuss the API, but otherwise, yes.

Check https://github.com/grpc/proposal

@theogravity
Copy link
Contributor

@anjmao
Copy link
Author

anjmao commented Aug 7, 2018

@theogravity Thanks for a link. I rewrote my server in go since it has the best grpc implementation.

@ShrawanLakhe
Copy link

any updates on server interceptors as of now? @nicolasnoble

@thodoris-tsiridis
Copy link

Hi, any updates?

@edvardchen
Copy link

Any updates about server interceptors?

@murgatroid99
Copy link
Member

Nobody has proposed an API design yet, so nothing has changed.

@richardpringle
Copy link
Contributor

Any updates here? Seems like interceptors would be pretty useful for things like auth and observability. Now that gRPC-web has hit 1.0, one could serve websites with gRPC and we'll need some sort of auth mechanism. It's not hard to roll your own interceptors, but it would be better if there was a standard way to do this.

@lwmxiaobei
Copy link

Any updates about server interceptors?

@anooshcnayak
Copy link

Any updates on this?

@loudmouth
Copy link

Also curious about this. Would be nice for rolling gRPC servers in Node to have some “official” support for interceptors

@Abhi347
Copy link

Abhi347 commented Nov 1, 2021

In case someone is interested and wants to support this, there're some discussion about this here - https://groups.google.com/g/grpc-io/c/sF8rO9ltkpA/m/qWC8an4IAwAJ

@huan
Copy link
Contributor

huan commented Nov 4, 2021

@Abhi347 thanks for pushing this moving forward, appreciate it!

@CMCDragonkai
Copy link

CMCDragonkai commented Nov 11, 2021

https://github.com/deeplay-io/nice-grpc/tree/master/packages/nice-grpc has implemented server side middleware for grpc-js.

@0101-0101
Copy link

Any updates about server interceptors?

@jiangtaoli2016
Copy link
Contributor

@murgatroid99 Any plan to implement interceptors on grpc-node server side?

@murgatroid99
Copy link
Member

We currently have no plans to implement server interceptors in the gRPC Node library.

@jakeowenp
Copy link

jakeowenp commented Oct 20, 2022

Hey @murgatroid99 - thanks for still being active on this thread

Do you have the grpc-node roadmap documented? I'm surprised after ~4 years interceptors have still have not been prioritised

Someone made a comment that you need a proposed API design - do you have a guide on contributing?

@murgatroid99
Copy link
Member

Do you have the grpc-node roadmap documented?

No. We don't really have a roadmap. It's really just team-level quarterly objectives. For the past couple of years, the main thing I have been working on is xDS features.

Someone made a comment that you need a proposed API design - do you have a guide on contributing?

The proposal process is described in the README in the https://github.com/grpc/proposal repository. Check out the Node client interceptors proposal for an example that is probably similar to what a server interceptors proposal might look like.

@TheBestOrNothing
Copy link

@murgatroid99 and other memeber of grpc. Please keep on going. The interceptors on the node server side is very importent for users authentication. Is there workaround about authentication with jwt (json web token)? Thanks.

@mfecteau42
Copy link

mfecteau42 commented May 19, 2023

Is there workaround about authentication with jwt (json web token)?

You may have an idea how to do it with this code :

const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');

const proxyHandler = {
    get(target, propKey) {
        if (propKey !== 'addService') {
            return target[propKey];
        }
        return (service, implementation) => {
            const newImplementation = {};
            const lookup = lookupServiceMetadata(service, implementation);
            for (const k in implementation) {
                const name = k;
                const fn = implementation[k];
                newImplementation[name] = (call, callback) => {
                    const ctx = {
                        call,
                        service: lookup(name),
                    };
                    const newCallback = callback => {
                        return (...args) => {
                            ctx.status = {
                                code: 0,//grpc.status.OK,
                            };
                            const err = args[0];
                            if (err) {
                                ctx.status = {
                                    code: 2,//grpc.status.UNKNOWN,
                                    details: err,
                                };
                            }
                            callback(...args);
                        };
                    };

                    const interceptors = target.intercept();
                    const first = interceptors.next();
                    if (!first.value) { // if we don't have any interceptors
                        return new Promise(resolve => {
                            return resolve(fn(call, newCallback(callback)));
                        });
                    }
                    first.value(ctx, function next() {
                        return new Promise(resolve => {
                            const i = interceptors.next();
                            if (i.done) {
                                return resolve(fn(call, newCallback(callback)));
                            }
                            return resolve(i.value(ctx, next, callback));
                        });
                    }, callback);
                };
            }
            return target.addService(service, newImplementation);
        };
    },
};

const proxyServer = (server) => {
  server.interceptors = [];
  server.use = fn => {
      server.interceptors.push(fn);
  };
  server.intercept = function* intercept() {
      let i = 0;
      while (i < server.interceptors.length) {
          yield server.interceptors[i];
          i++;
      }
  };
  return new Proxy(server, proxyHandler);
}

function startServer() {

    const protoDefinition = protoLoader.loadSync("PATH_TO_PROTOFILE",
            {
                keepCase: true,
                longs: String,
                enums: String,
                defaults: true,
                oneofs: true,
            });
        const proto = grpc.loadPackageDefinition(protoDefinition);
        const server = proxyServer(new grpc.Server());

      async function login(call, callback) {
          // login code where you generate a token for the session, etc. ...
      }

       server.addService( proto.myservice, login); // ... adaptation necessary

       //middleware function that will be called before each grpc methods
        const grpcInterceptor = async (ctx, next, callback) => {
            function copyMetadata(call) {
                const metadata = call.metadata.getMap();
                const responseMetadata = new grpc.Metadata();
                for (let key in metadata) {
                    responseMetadata.set(key, metadata[key]);
                }
                return responseMetadata;
            }
            //token passed by http metadata
            const token = ctx.call.metadata.internalRepr.get("token")[0]
            
            // ... block of code to validate token, etc.
            let validated = true;

            // if all is well, we call original grpc method
            if (validated) {
                await next();
            } else {
                  error = new Error("Invalid token");
                  error.code = 16; //UNAUTHENTICATED
                  callback(error);
            }           
        };

    
        server.use(grpcInterceptor);
        server.bindAsync(address, grpc.ServerCredentials.createInsecure(), (err, result) => !err ? server.start() : console.error(err));
       
}

startServer();


update : added syntax highlighting to the code example. Thanks to @richardpringle.

@richardpringle
Copy link
Contributor

@mfecteau42, use ```js to get syntax highlighting in your code example

@murgatroid99
Copy link
Member

I have proposed a design for a server interceptors API: grpc/proposal#406. If you have any feedback on the design please comment there.

@vincen7tran
Copy link

@murgatroid99 do you plan to merge these changes soon as they are approved? thanks for proposing a design! 🙏

@murgatroid99
Copy link
Member

Our convention is to have a review period of at least two weeks before finalizing a proposal. I am working on the implementation in parallel to the proposal review, and even once the proposal is accepted it will still take me some time to finish the implementation.

@murgatroid99
Copy link
Member

Update: the design proposal grpc/proposal#406 is going through final review next week, and the implementation PR is out at #2650.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.