[GH-ISSUE #6838] session IP always returns 127.0.0.1 in test/dev #19280

Closed
opened 2026-04-15 18:09:43 -05:00 by GiteaMirror · 3 comments
Owner

Originally created by @renshoenen on GitHub (Dec 17, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/6838

Originally assigned to: @bytaesu on GitHub.

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

I spend hours trying to figure out why the session IP was 127.0.0.1.
After finally inspecting the code, I found it's hardcoded for when running in dev/test:
This file has code:

if (isTest() || isDevelopment()) { return LOCALHOST_IP; }

My development server runs with a proxy in front, which is why expected 'real' ip addresses.
A recent issue also misled me; This issue mentioned

Better Auth does not automatically populate the ipAddress and userAgent fields in sessions for emailAndPassword authentication in Next.js.

Current vs. Expected behavior

I would expect dev mode would use the headers (if available) and use the default value only as fallback.
Alternatively, if unwanted for any reason, maybe update the docs to reflect this behaviour.

What version of Better Auth are you using?

1.4.7

System info

{
  "system": {
    "platform": "linux",
    "arch": "x64",
    "version": "#1 SMP PREEMPT_DYNAMIC PMX 6.8.12-9 (2025-03-16T19:18Z)",
    "release": "6.8.12-9-pve",
    "cpuCount": 4,
    "cpuModel": "12th Gen Intel(R) Core(TM) i5-1240P",
    "totalMemory": "8.00 GB",
    "freeMemory": "3.15 GB"
  },
  "node": {
    "version": "v22.17.1",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "11.4.2"
  },
  "frameworks": [
    {
      "name": "vue",
      "version": "^3.5.24"
    },
    {
      "name": "nuxt",
      "version": "^4.2.1"
    }
  ],
  "databases": [
    {
      "name": "pg",
      "version": "^8.16.3"
    },
    {
      "name": "@prisma/client",
      "version": "^7.1.0"
    }
  ],
  "betterAuth": {
    "version": "^1.4.7",
    "config": null
  }
}

Which area(s) are affected? (Select all that apply)

Backend

Auth config (if applicable)

import { betterAuth } from "better-auth"
export const auth = betterAuth({
  emailAndPassword: {  
    enabled: true
  },
});

Thanks for the great work!

Additional context

No response

Originally created by @renshoenen on GitHub (Dec 17, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/6838 Originally assigned to: @bytaesu on GitHub. ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce I spend hours trying to figure out why the session IP was 127.0.0.1. After finally inspecting the code, I found it's hardcoded for when running in dev/test: [This file](https://github.com/better-auth/better-auth/blob/canary/packages/better-auth/src/utils/get-request-ip.ts) has code: `if (isTest() || isDevelopment()) { return LOCALHOST_IP; }` My development server runs with a proxy in front, which is why expected 'real' ip addresses. A recent issue also misled me; [This issue](https://github.com/better-auth/better-auth/issues/4782) mentioned > Better Auth does not automatically populate the ipAddress and userAgent fields in sessions for emailAndPassword authentication in Next.js. ### Current vs. Expected behavior I would expect dev mode would use the headers (if available) and use the default value only as fallback. Alternatively, if unwanted for any reason, maybe update the docs to reflect this behaviour. ### What version of Better Auth are you using? 1.4.7 ### System info ```bash { "system": { "platform": "linux", "arch": "x64", "version": "#1 SMP PREEMPT_DYNAMIC PMX 6.8.12-9 (2025-03-16T19:18Z)", "release": "6.8.12-9-pve", "cpuCount": 4, "cpuModel": "12th Gen Intel(R) Core(TM) i5-1240P", "totalMemory": "8.00 GB", "freeMemory": "3.15 GB" }, "node": { "version": "v22.17.1", "env": "development" }, "packageManager": { "name": "npm", "version": "11.4.2" }, "frameworks": [ { "name": "vue", "version": "^3.5.24" }, { "name": "nuxt", "version": "^4.2.1" } ], "databases": [ { "name": "pg", "version": "^8.16.3" }, { "name": "@prisma/client", "version": "^7.1.0" } ], "betterAuth": { "version": "^1.4.7", "config": null } } ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript import { betterAuth } from "better-auth" export const auth = betterAuth({ emailAndPassword: { enabled: true }, }); ``` Thanks for the great work! ### Additional context _No response_
GiteaMirror added the lockedenhancement labels 2026-04-15 18:09:43 -05:00
Author
Owner

@better-auth-agent[bot] commented on GitHub (Dec 17, 2025):

tag @better-auth-agent if you would like an answer from the Agent

If you need more help, tag @better-auth-agent in a comment so I can respond.

DiagramDiscordGitHub

Diagram Join Star

<!-- gh-comment-id:3667245356 --> @better-auth-agent[bot] commented on GitHub (Dec 17, 2025): tag @better-auth-agent if you would like an answer from the Agent _If you need more help, tag @better-auth-agent in a comment so I can respond._ <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) • [Discord](https://discord.gg/fG2XXEuQX3) • [GitHub](https://github.com/Skyvern-AI/Skyvern) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/fG2XXEuQX3) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/Skyvern-AI/Skyvern)
Author
Owner

@dosubot[bot] commented on GitHub (Dec 17, 2025):

Hi @Racusthor! I'm Dosu and I’m helping the better-auth team.

This is intentional: Better Auth always returns 127.0.0.1 as the session IP in development and test environments, as hardcoded in get-request-ip.ts. This was added to ensure rate limiting works reliably in local setups, where real client IPs are often unavailable or indeterminate. The code checks isTest() or isDevelopment() and immediately returns the localhost IP before inspecting any headers, even if you’re behind a proxy or forwarding X-Forwarded-For or similar headers [PR #5436, PR #2511].

There’s currently no config option to override this in v1.4.7 or newer; the advanced.ipAddress.ipAddressHeaders setting only affects production. If you need real IPs in dev/test, you’ll need a workaround: inject the IP at the proxy layer, use a custom middleware to set a header, or override the session IP using databaseHooks (see example). Several users have requested a toggle or config for this, but it’s not supported out of the box [discussion, issue #2633].

Docs don’t clearly state this behavior yet, so updating them or adding a code comment would help clarify for others. If you want to mimic production IP detection in dev, overriding via databaseHooks or patching the library is the most direct path for now.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:3667259780 --> @dosubot[bot] commented on GitHub (Dec 17, 2025): <!-- Greeting --> Hi @Racusthor! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> This is intentional: Better Auth always returns `127.0.0.1` as the session IP in development and test environments, as hardcoded in [`get-request-ip.ts`](https://github.com/better-auth/better-auth/blob/canary/packages/better-auth/src/utils/get-request-ip.ts). This was added to ensure rate limiting works reliably in local setups, where real client IPs are often unavailable or indeterminate. The code checks `isTest()` or `isDevelopment()` and immediately returns the localhost IP before inspecting any headers, even if you’re behind a proxy or forwarding `X-Forwarded-For` or similar headers [[PR #5436](https://github.com/better-auth/better-auth/pull/5436), [PR #2511](https://github.com/better-auth/better-auth/pull/2511)]. There’s currently no config option to override this in v1.4.7 or newer; the `advanced.ipAddress.ipAddressHeaders` setting only affects production. If you need real IPs in dev/test, you’ll need a workaround: inject the IP at the proxy layer, use a custom middleware to set a header, or override the session IP using `databaseHooks` (see [example](https://github.com/better-auth/better-auth/issues/4782)). Several users have requested a toggle or config for this, but it’s not supported out of the box [[discussion](https://github.com/better-auth/better-auth/discussions/3865), [issue #2633](https://github.com/better-auth/better-auth/issues/2633)]. Docs don’t clearly state this behavior yet, so updating them or adding a code comment would help clarify for others. If you want to mimic production IP detection in dev, overriding via `databaseHooks` or patching the library is the most direct path for now. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/5453feda-3541-4b18-806e-4b86ce908e58?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/5453feda-3541-4b18-806e-4b86ce908e58?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/5453feda-3541-4b18-806e-4b86ce908e58?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/5453feda-3541-4b18-806e-4b86ce908e58?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/5453feda-3541-4b18-806e-4b86ce908e58?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/5453feda-3541-4b18-806e-4b86ce908e58?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/5453feda-3541-4b18-806e-4b86ce908e58?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=This%20is%20intentional%3A%20Better%20Auth%20always%20returns%20%60127.0.0.1%60%20as%20the%20session%20IP%20in%20development%20and%20test%20environments%2C%20as%20hardcoded%20in%20%5B%60get-request-ip.ts%60%5D%28https%3A//github.com/better-auth/better-auth/blob/canary/packages/better-auth/src/utils/get-request-ip.ts%29.%20This%20was%20added%20to%20ensure%20rate%20limiting%20works%20reliably%20in%20local%20setups%2C%20where%20real%20client%20IPs%20are%20often%20unavailable%20or%20indeterminate.%20The%20code%20checks%20%60isTest%28%29%60%20or%20%60isDevelopment%28%29%60%20and%20immediately%20returns%20the%20localhost%20IP%20before%20inspecting%20any%20headers%2C%20even%20if%20you%E2%80%99re%20behind%20a%20proxy%20or%20forwarding%20%60X-Forwarded-For%60%20or%20similar%20headers%20%5B%5BPR%20%235436%5D%28https%3A//github.com/better-auth/better-auth/pull/5436%29%2C%20%5BPR%20%232511%5D%28https%3A//github.com/better-auth/better-auth/pull/2511%29%5D.%0A%0AThere%E2%80%99s%20currently%20no%20config%20option%20to%20override%20this%20in%20v1.4.7%20or%20newer%3B%20the%20%60advanced.ipAddress.ipAddressHeaders%60%20setting%20only%20affects%20production.%20If%20you%20need%20real%20IPs%20in%20dev/test%2C%20you%E2%80%99ll%20need%20a%20workaround%3A%20inject%20the%20IP%20at%20the%20proxy%20layer%2C%20use%20a%20custom%20middleware%20to%20set%20a%20header%2C%20or%20override%20the%20session%20IP%20using%20%60databaseHooks%60%20%28see%20%5Bexample%5D%28https%3A//github.com/better-auth/better-auth/issues/4782%29%29.%20Several%20users%20have%20requested%20a%20toggle%20or%20config%20for%20this%2C%20but%20it%E2%80%99s%20not%20supported%20out%20of%20the%20box%20%5B%5Bdiscussion%5D%28https%3A//github.com/better-auth/better-auth/discussions/3865%29%2C%20%5Bissue%20%232633%5D%28https%3A//github.com/better-auth/better-auth/issues/2633%29%5D.%0A%0ADocs%20don%E2%80%99t%20clearly%20state%20this%20behavior%20yet%2C%20so%20updating%20them%20or%20adding%20a%20code%20comment%20would%20help%20clarify%20for%20others.%20If%20you%20want%20to%20mimic%20production%20IP%20detection%20in%20dev%2C%20overriding%20via%20%60databaseHooks%60%20or%20patching%20the%20library%20is%20the%20most%20direct%20path%20for%20now.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/6838)
Author
Owner

@bytaesu commented on GitHub (Dec 18, 2025):

Hello @Racusthor,

In the local dev (localhost) environment, the IP address from headers is undefined, so a previous request to fix this has been applied!

It will be undefined in most cases, but I’ll add a check to see if an IP exists in development/test environments as well

<!-- gh-comment-id:3668669937 --> @bytaesu commented on GitHub (Dec 18, 2025): Hello @Racusthor, In the local dev (localhost) environment, the IP address from headers is undefined, so a previous request to fix this has been applied! It will be undefined in most cases, but I’ll add a check to see if an IP exists in development/test environments as well
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#19280