Getting source ip / remote ip in the JS Middleware

Hi
I have successfully configured a route /a/b on my tyk gateway and added a JS pre middleware that will send a post request to another service on my application.
the post request that I send includes the all the data that I can get from the original request /a/b
but it does not include the source ip.

so I have checked the logs of tyk , and they include the source ip , so tyk knows it

also the final request that reaches the target url which is a server that responds to /a/b
the server can see X-FORWARDED-FOR header with the correct value.
while the request object in the middleware does not have that header , so it seems tyk adds it later on

I have seen that there is context variables , but I could not access them
can I access them in JS middleware ? HOW ?
So , The main question is how do I access the origin ip in a JS middleware ?

https://tyk.io/docs/context-variables/

included the middleware js code

var middleware = new TykJS.TykMiddleware.NewMiddleware({});

middleware.NewProcessRequest(function(request, session, spec) {
    console.log("Middleware running");
    console.log(JSON.stringify(request))
    console.log("Middleware running - request log end");
    console.log(JSON.stringify(session))
    console.log("Middleware running - session log end");
    console.log(JSON.stringify(spec))
    console.log("Middleware running - spec log end");
    console.log('request.Headers["X-Forwarded-For"]')
    console.log(request.Headers["X-Forwarded-For"])
    console.log('request.Headers["x-forwarded-for"]')
    console.log(request.Headers["x-forwarded-for"])
    var post_data = {
        "method": request.Method,
        "headers": request.Headers,
        "body": request.Body,
        "url": request.URL
    };

    var newRequest = {
        "Method": "POST",
        "Body": JSON.stringify(post_data) , 
        "Headers": {"Content-Type": "application/json",
                    "x-remote-addr": "$tyk_context.remote_addr"
                   },
        "Domain": "http://10.0.8.3:3000",
        "Resource": "/c/d",
        "FormData": {}
    };

    TykMakeHttpRequest(JSON.stringify(newRequest));

    return middleware.ReturnData(request,session.meta_data) //TykJsResponse({Body: "", Code: 200}, session.meta_data);
});
DoProcessRequest = middleware.DoProcessRequest;
console.log("hiyou_middleware.js loaded");


Hello @Rabea and welcome to the community.

From what you’ve explained, it sounds like you are halfway there. You can use JS plugin along with transform headers and context variables. As you mentioned your IP gets upstream, so that means Tyk is adding it somewhere.

Our transform headers middleware can set or unset headers before they are sent upstream. This section is probably where you want to map the remote_addr header from the context variable to a new header i.e. something like x-forwarded-for or x-ip-list. Then retrieve the exposed header from the JS plugin.

Note
This suggestion takes into account that the execution order of the transform headers in the request lifecycle.

There are other possibilities you could use. I have outlined and summarized 4 possible options including the one suggested above you could end up with:

  1. Execute your JS plugin in the custom post (request) middleware to retrieve the exposed header, since JS plugin engine is restricted to only pre and post. Context variables are not available in pre middleware lifecycle for any plugin other than native Golang.
  2. Find a way to retrieve the IP before it’s sent to Tyk. You could pass it directly in a header or within some proxy in that retrieves that before it’s sent to the gateway. I believe nginx is a good example here as discussed in our article on creating an IP-based rate-limiter with Tyk and JavaScript middleware.
  3. Use another API definition (A) as the proxy and retrieve the value of the IP in the post middleware. Then URL rewrite to your desired API definition (B) with looping. The header value should be available in the pre request of B.
  4. Rethink using JS and use Golang to do it instead. Of course this may affect the API design of your other APIs. The nice thing is that the IP can be retrieved from the pre request middleware scope in Golang.

Golang snippet

// AddFooBarHeader adds custom "Foo: Bar" header to the request 
func AddFooBarHeader(rw http.ResponseWriter, r *http.Request) { 
  logger.Info("Processing HTTP request in Golang plugin!!") 
  
  // get origin ip address of request 
  requestOrigin := r.RemoteAddr 
  
  // Add origin ip to custom header 
  r.Header.Add("X-Ip-Address", requestOrigin) 
} 

func main() {}