Finastra / finastra-nodejs-libs

A set of opinionated libraries for building efficient and scalable server-side applications with Node.js
MIT License
36 stars 14 forks source link

nestjs-proxy - appending query params #264

Closed julianmclean closed 1 year ago

julianmclean commented 1 year ago

I'm trying to use nestjs-proxy to add a proxy to my NestJS backend that can be used by a React Native frontend library to access the Google Places API, which supports using a proxy - this one: https://github.com/FaridSafi/react-native-google-places-autocomplete

I'm doing this so I can hold the google places API key in the backend and it doesn't need to be exposed in the frontend code.

Ultimately the request needs to go here:

https://maps.googleapis.com/maps/api/place/autocomplete/json?input=<address>&key=<google places api key>

Note that the api key is passed as a query param, not a header.

I have setup the proxy using the instructions like this:

    ProxyModule.forRoot({
      config: {},
      services: [
        {
          id: 'GOOGLE_MAPS',
          url: `https://maps.googleapis.com/maps/api/`,
          config: {},
        },
      ],
    }),

The incoming request is like this: /proxy?serviceId=GOOGLE_MAPS&target=place/autocomplete/json?input=<address which I can see is proxied to the real endpoint, however I am struggling to append the required api key (as another query param) on the way through. I can see options for adding headers, but nothing about how to add query params?

I've looked the options here to add to config and can't find anything either: https://github.com/http-party/node-http-proxy#options

Is it possible to do what I need?

bcldvd commented 1 year ago

Hi @julianmclean !

It seems that your API is meant to be publicly exposed on the front end: https://developers.google.com/maps/api-security-best-practices#restrict_apikey

You'd want to restrict the referers to your own domain(s) only though ;)

julianmclean commented 1 year ago

It seems that your API is meant to be publicly exposed on the front end: https://developers.google.com/maps/api-security-best-practices#restrict_apikey Not 100% sure what you mean by this? My backend proxy API will (probably) be publicly available, but I'm talking about injecting the API key for Google Places in my backend so that it is not stored in the frontend app (not any key/token to access MY backend). The issue is that Google Places wants their API key in the query params, and I can't find a way to inject that on the way through. I found some documentation suggesting that the API key could be places in a header (x-api-key) but this doesn't seem to actually work.

You'd want to restrict the referrers to your own domain(s) only though ;) I've looked into this but it isn't actually supported by the Google Places web services api. I can only use IP addresses which is not very practical with a backend sitting (anywhere) on AWS.

I appreciate you directing me down other paths, however question still stands as to whether there is a way to modify query params on the way through (as can be done for headers). Slightly related to this, I've noticed that if the target path contains query params, the HTTP encoding handling is perhaps a little inconsistent? Examples:

This makes it difficult to pass through multiple query params (which would be the API "key" in my case, if I wanted to retain the key in the frontend, pass via proxy and try to lock down google places API access to my backend). Whilst in principle I could encode client-side, this is buried in the library (https://github.com/FaridSafi/react-native-google-places-autocomplete) so I don't have control to change it.

Caught between a few issues here and trying to find a way through ;o)

bcldvd commented 1 year ago

I meant that the API Key is intended to be publicly exposed on the front end.

Since it will be restricted from being used by anything other than what you've defined as an authorized referrer, even if an evil intended person were to try to use it, they couldn't, unless they had access to your domain and were able to initiate their request from there.

As per the referrers themselves, the documentation clearly states it accepts domains:

image

If it actually doesn't allow it, indeed, using AWS will make it very cumbersome :(

As for your initial need to add additional query params to your requests, I do not see options for it in the original node-http-proxy library. Unless they add it, this is not something we intend to support on our end. But if you feel up to the task, you can try to make a Pull Request on node-http-proxy!