Can I get the IP address of my users in a SvelteKit project?

Viewed 1076

I'm interested in capturing the Internet Protocol (IP) address of my users at their initial submit to my website. I was under the impression that a SvelteKit submit would be similar to other node.js server solution.

I've been all over this posting, and I'm just not seeing anything remotely like req.headers['x-forwarded-for'] or req.socket.remoteAddress in my request submit to API server in SvelteKit.

Here's what I do see in the request (via a console log in the API submit):

arg1:
    body: (... data ... )
    Headers:
        accept:'*/*'
        accept-encoding:'gzip, deflate'
        accept-language:'en-US,en;q=0.9'
        connection:'keep-alive'
        content-length:'141'
        content-type:'text/plain;charset=UTF-8'
        cookie:'userid=c03efd10-3085-46cb-bacd-9eaeb605426e'
        host:'192.168.1.22:3000'
        origin:'http://192.168.1.22:3000'
        referer:'http://192.168.1.22:3000/learn'
        user-agent:'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36'
    locals:
        userid: '....'
    method: 'POST'
    params: {}
    path: '/api/user_form'
    query: ...
    rawBody: ... 

Definitely no socket, no header for ['x-forwarded-for']

Note, I'm working this on local network. Host on one machine, client on another machine in the same network. In fact, host = 192.168.1.22:3000, client = 192.168.1.4

Note2, I'm running the program via svelte-kit dev --host 0.0.0.0

What am I not seeing? Is there a way to obtain a client user's IP address from a websubmit using Sveltekit?

3 Answers

Everything below is for production / build code.

> npm run build
> node build

Running your app in dev mode is different due to VITE.


The Svelte Adapter receives a Node Request which also includes the remote IP. The IP could be extracted with the methods mentioned here.

The Adapter however only forwards the values required for the Svelte IncomingRequest interface to the Svelte Render. This interface is then further extended by Svelte to a Request interface and includes the following values:

export interface Request<Locals = Record<string, any>, Body = unknown> {
    url: URL;
    method: string;
    headers: RequestHeaders;
    rawBody: RawBody;
    params: Record<string, string>;
    body: ParameterizedBody<Body>;
    locals: Locals;
}

Therefore, I see four possible ways to tackle this issue:

  1. Create an issue to update the Svelte IncomingRequest interface to include the remote IP. (This would also require an update in all Adapters)
  2. Create your own Middleware as an entry point for your application. The downside is, that you still wont get the remote IP anywhere in your Svelte handle or routes. You could however log the IP or block certain paths.
  3. Run your app behind a proxy, the proxy would populate ['x-forwarded-for'] in the request header and as shown in the interface above, the header is available in your Svelte Request object.
  4. Modify the Svelte IncomingRequest interface and Adapter Middleware on your own. (This is dirty and a mess to maintain)

Since 2. is the most applicable way, here is an example on how to set it up with polka - you could of course also use express or any other HTTP server.

/src/server.js file which is our Middleware in this case:

import polka from 'polka'
import { assetsMiddleware, prerenderedMiddleware, kitMiddleware } from '../build/middlewares.js'

const { PORT, DOMAIN } = process.env

polka()
  .use((req, res, next) => {
      console.log(req.socket.remoteAddress);
    next()
  })

  // Load the SvelteKit build
  .use(assetsMiddleware, prerenderedMiddleware, kitMiddleware)

  .listen(PORT)

/svelte.config.js to configure our Middleware as the entryPoint - minimal example using the default adapter-node:

import preprocess from 'svelte-preprocess';
import adapter from '@sveltejs/adapter-node';

/** @type {import('@sveltejs/kit').Config} */
const config = {
    preprocess: preprocess(),

    kit: {
        adapter: adapter({ entryPoint: './src/server.js' }),
        target: '#svelte'
    }
};

export default config;
Related