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

IP address not obtainable in Next 13 with app dir? #47793

Closed
1 task done
xriter opened this issue Apr 1, 2023 · 34 comments
Closed
1 task done

IP address not obtainable in Next 13 with app dir? #47793

xriter opened this issue Apr 1, 2023 · 34 comments
Labels
area: app App directory (appDir: true) bug Issue was opened via the bug report template. locked

Comments

@xriter
Copy link

xriter commented Apr 1, 2023

Verify canary release

  • I verified that the issue exists in the latest Next.js canary release

Provide environment information

Operating System:
      Platform: darwin
      Arch: arm64
      Version: Darwin Kernel Version 22.4.0: Mon Mar  6 21:00:41 PST 2023; root:xnu-8796.101.5~3/RELEASE_ARM64_T8103
    Binaries:
      Node: 16.15.0
      npm: 8.10.0
      Yarn: 1.22.15
      pnpm: 6.11.0
    Relevant packages:
      next: 13.2.4
      eslint-config-next: 13.0.4
      react: 18.2.0
      react-dom: 18.2.0

Describe the Bug

It seems to be undoable to get the users IP address when using Next 13 with the app dir.

  • Server Components don't get the req.ip or req.geo property.
  • When using route handlers, req.ip is undefined and req.geo is {}.

How is one supposed to get the ip address on the server side in Next 13?

@xriter xriter added the bug Issue was opened via the bug report template. label Apr 1, 2023
@github-actions github-actions bot added the area: app App directory (appDir: true) label Apr 1, 2023
@pdong
Copy link

pdong commented Apr 2, 2023

On NextRequest, geo and ip are empty/undefined unless provided by the hosting platform as documented here:

https://nextjs.org/docs/api-reference/next/server#nextrequest

ip: (string || undefined) - Has the IP address of the Request. This information is provided by your hosting platform.

geo - Has the geographic location from the Request. This information is provided by your hosting platform.

@pogran
Copy link

pogran commented Jun 9, 2023

it doesnt work. my server send to headers to request X-Real-IP and X-Forwarded-For but ip underfined...

@jmif
Copy link

jmif commented Jun 22, 2023

We're having this issue too. Is there a way to get the request IP when using app router?

@JoshAllen95
Copy link

@jmif Did you find a workaround or a way of doing this?

@Bitbbot
Copy link
Contributor

Bitbbot commented Jul 27, 2023

Still relevant problem

@Bitbbot
Copy link
Contributor

Bitbbot commented Jul 27, 2023

what's the point of having fucking api routes if u can't get an ip?

@fywk
Copy link

fywk commented Jul 27, 2023

You can still access the ip address in api routes (and middleware) of the page router, according to the doc. The issue here is that it's not available for the app router.

@Bitbbot
Copy link
Contributor

Bitbbot commented Jul 27, 2023

You can still access the ip address in api routes (and middleware) of the page router, according to the doc. The issue here is that it's not available for the app router.

Cool! Rewriting the whole app on the old version is exactly what I want, ahahha. I'm quite pissed off frankly speaking

@fywk
Copy link

fywk commented Jul 27, 2023

You can still access the ip address in api routes (and middleware) of the page router, according to the doc. The issue here is that it's not available for the app router.

Cool! Rewriting the whole app on the old version is exactly what I want, ahahha. I'm quite pissed off frankly speaking

Yes, api routes are the remaining bits that I've yet to move to route handlers in the app router because of this. It would be great if ip and geo properties would get supported soon.

As for workaround, I'm currently using middleware to add geo info to searchParams:

import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { app } from "./lib/app-config";

export const config = {
  matcher: ["/"],
};

export function middleware(request: NextRequest) {
  const { nextUrl: url, geo } = request;

  const city = geo?.city ?? app.location.city;
  const country = geo?.country ?? app.location.country;

  url.searchParams.set("city", city);
  url.searchParams.set("country", country);

  return NextResponse.rewrite(url);
}

Then, in my app/page.tsx:

export default function Page({ searchParams }: SearchParams) {
  const city = searchParams.city;
  ...
}

@mindaras
Copy link

mindaras commented Aug 4, 2023

You can get the ip related headers in your server component by using headers() from "next/headers", convert it to object literal and pass it to your fetch request which is calling your api route. I'd suggest making an api client wrapper to do this automatically.

import { headers } from "next/headers";

...

const response = await fetch(`${baseUrl}/api${path}`, {
  ...options,
  headers: Object.fromEntries(headers())
});

@Bitbbot
Copy link
Contributor

Bitbbot commented Aug 7, 2023

You can get the ip related headers in your server component by using headers() from "next/headers", convert it to object literal and pass it to your fetch request which is calling your api route. I'd suggest making an api client wrapper to do this automatically.

import { headers } from "next/headers";

...

const response = await fetch(`${baseUrl}/api${path}`, {
  ...options,
  headers: Object.fromEntries(headers())
});

Won't I be able to forge headers in a request like this? Pass not real ip for instance

@mindaras
Copy link

mindaras commented Aug 7, 2023

You can get the ip related headers in your server component by using headers() from "next/headers", convert it to object literal and pass it to your fetch request which is calling your api route. I'd suggest making an api client wrapper to do this automatically.

import { headers } from "next/headers";

...

const response = await fetch(`${baseUrl}/api${path}`, {
  ...options,
  headers: Object.fromEntries(headers())
});

Won't I be able to forge headers in a request like this? Pass not real ip for instance

This approach only applies to server components since headers util is only accessible from the server, so client wouldn't be able to tamper with it. When the request is coming from the client-side, the headers are already present. The issue is that when you call your own API on the server-side, the headers aren't being forwarded automatically.

@raflymln
Copy link

In some cases, "X-Real-IP" and "X-Forwarded-For" returns undefined, i think NextJS team should implement this on NextRequest, i don't understand what's their intention or plan on NextRequest.ip variable if we can't get the IP, kinda stupid enough

@Bitbbot
Copy link
Contributor

Bitbbot commented Aug 23, 2023

"X-Real-IP" and "X-Forwarded-For"

If I'm not mistaken, there has to be some configuration on the server e.g. nginx to get an ip

@raflymln
Copy link

"X-Real-IP" and "X-Forwarded-For"

If I'm not mistaken, there has to be some configuration on the server e.g. nginx to get an ip

Yes, if you were using nginx, if not?

@Cyral
Copy link

Cyral commented Aug 27, 2023

Testing out the app router for the first time today and ran into this issue as I need to make external requests in my components during SSR. I have a backend written in another language and previously used getServerSideProps to call fetch, passing the user's IP, cookies, etc. so that the backend would see the request as coming from the end user and not localhost (nextjs).

The whole caching and data fetching story with the app router is a bit complicated, but I think I figured out how to do this. Using "next/headers" as mentioned above we can get the headers (similar to appContext with the pages router) and pass them to fetch, the problem occurs when this is used in a client component. (The file that imports headers to create the fetch request, among other custom fetch additions, is used for both client and server requests) You will get an error that you cannot use headers in client components. To work around this, we need to dynamically import the headers module.

Change import {headers} from 'next/headers' to const headers = import('next/headers'); and conditionally call it if the window is undefined:

let ssrHeaders = {};
if (typeof window === 'undefined') {
  ssrHeaders = Object.fromEntries((await headers).headers());
}

Then pass these headers to fetch to forward them to your backend. This is all behind nginx so x-forwarded-for is trusted.

@Arunjenson-ss
Copy link

is it fixed ?

@hongz1
Copy link

hongz1 commented Sep 7, 2023

No solution so far??

@reginpv
Copy link

reginpv commented Sep 7, 2023

waiting for this

@OlegLustenko
Copy link

It seems this is related PR

#54813

@hongz1
Copy link

hongz1 commented Sep 15, 2023

@OlegLustenko I tried 'v13.4.20-canary.31' and request.ip is still undefined and request.geo is empty object.
I was able to get client ip from express with react via axios.
My question is that there is no way to get client Ip in middleware or nextjs API route handler using fetch for app dir unless I have to use 3rd-party like ipify ?

@larevuegeek
Copy link

Hello, i have the same problem also.
Inside the request, the IP value is undefined.
I just start a new app, so for investigate I have test to create a fresh App With the old Pages Router, and i can get the IP now via getServerSideProps.
I don't know if this information can help.

@hongz1
Copy link

hongz1 commented Sep 19, 2023

Hello, I tried this workaround and it's working for me. Inside the middleware, I use fetch to an external API (or Pages API) that will return the IP/geo.


  export async function middleware(req: NextRequest) {

        const res = NextResponse.next();



        let geoIp = await fetch("https://geolocation-db.com/json/").then((response) =>

          response.json(),

        );



        if (geoIp) {

          res.headers.set("x-forwarded-for", geoIp.IPv4);

          res.headers.set("x-real-ip", geoIp.IPv4);

      

          let geo = geoIp;

          delete geo.IPv4;

      

          res.headers.set("geo", JSON.stringify(geo));

        };



        return res;

}

That is not what we are discussing here. Yes you can get ip from 3rd party. When client side sends request, server side doesn't get ip.

Try create react and express and send request to express using axios. You gonna get ip even in local host. In nextjs, there is no way to get ip now unless your web server like nginx has configured or send another request to 3rd party to get ip.

@vnevermore
Copy link

vnevermore commented Sep 19, 2023

The wierd thing is that the past few days i was using this aproach on a page.tsx

import { headers } from "next/headers";

const headersList = headers();
onst ip = headersList.get("x-forwarded-for");

and it was working just fine until today where "x-forwarded-for" is not included anymore on the headers array
i've updated to latest from "13.4.12" and i am talking about running on localhost dev

@gtokman

This comment has been minimized.

@ekatzenstein
Copy link

My dudes, this needs to be fixed. It's a fundamental issue.

@yasincandev

This comment has been minimized.

@sam3d
Copy link
Contributor

sam3d commented Oct 13, 2023

The x-forwarded-for header seems to work in production (if you're querying it from any machine that isn't localhost).

@sam3d
Copy link
Contributor

sam3d commented Oct 17, 2023

I think this may have been fixed with #56797?

@Zerebokep
Copy link

I think we still need a way to securely get the ip of the proxy (not the visitors ip) if a reverse proxy is used in front of nextjs, correct me if I'm wrong.

@leerob
Copy link
Member

leerob commented Dec 17, 2023

Hey everyone, I can confirm that was fixed with #56797. Further, heard on the feedback here that this was not clearly documented, especially around the usage of request.ip vs. reading the headers directly.

I've updated the docs based on this issue as well: #59719

Thank you 🙏

@Zerebokep
Copy link

@leerob I haven't found any update regarding request.ip, could you please clarify if it is possible to obtain the ip of the actual request without relying on headers? If this is not possible all non-enterprise vercel app's are basically prone to spoofing.

It seems the edge helper function also gets the ip from the headers:

https://vercel.com/docs/functions/edge-middleware/middleware-api#ipaddress

The ipAddress helper returns the IP address of the request from the headers.

Imho this issue shouldn't be closed until there is a solution for this, as it is a security issue.

leerob added a commit that referenced this issue Dec 18, 2023
Based on feedback from #47793, I
made some improvements around the geolocation docs. Specifically around
`request.ip`, `request.geo`, and how to access these values. I noticed
there was a bit of a divergence, as some of the `NextRequest` and
`NextResponse` docs were split out for the App Router section, but not
all.

This PR finishes that swing by removing the previous catch-all for
`next/server` in the Pages Router docs and splits them into individual
docs pages.

Wrote a lil' thread about this:
https://twitter.com/leeerob/status/1736543599339172121

---------

Co-authored-by: Delba de Oliveira <32464864+delbaoliveira@users.noreply.github.com>
@leerob
Copy link
Member

leerob commented Dec 18, 2023

@Zerebokep this issue is around getting the IP address with the App Router. This is possible and now more clearly documented. request.ip specifically is a helper method on top of reading the headers, so no, it is not possible to get this value on Vercel without using the headers.

You are correct that x-forwarded-for can be spoofed, and there's some good documentation here with more details. If you need Vercel to be a trusted reverse proxy, this does require an Enterprise plan.

Copy link
Contributor

github-actions bot commented Jan 2, 2024

This closed issue has been automatically locked because it had no new activity for 2 weeks. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@github-actions github-actions bot added the locked label Jan 2, 2024
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jan 2, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: app App directory (appDir: true) bug Issue was opened via the bug report template. locked
Projects
None yet
Development

No branches or pull requests