[GH-ISSUE #8615] rate-limiter produces confusing warning #11136

Closed
opened 2026-04-13 07:30:20 -05:00 by GiteaMirror · 1 comment
Owner

Originally created by @ic4l4s9c on GitHub (Mar 15, 2026).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/8615

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

The reproduction steps should not really matter since the issue is not with me seeing the warning message, but with incorrect/confusing content.

Current vs. Expected behavior

Current behavior:

WARN [Better Auth]: Rate limiting skipped: could not determine client IP address. If you're behind a reverse proxy, make sure to configure `trustedProxies` in your auth config.'

The problem is there is no trustedProxies option anywhere in better-auth; the only place it's mentioned is #8006.

Expected behavior:
The warning message should align with the documentation and mention either trustedProxyHeaders or trustedOrigins or other relevant config options (that can be found in the docs).

What version of Better Auth are you using?

1.5.3

System info

{
  "system": {
    "platform": "linux",
    "arch": "x64",
    "version": "#1 SMP PREEMPT_DYNAMIC Mon, 09 Feb 2026 17:16:33 +0000",
    "release": "6.18.9-arch1-2",
    "cpuCount": 32,
    "cpuModel": "AMD Ryzen 9 9950X3D 16-Core Processor",
    "totalMemory": "186.34 GB",
    "freeMemory": "147.53 GB"
  },
  "node": {
    "version": "v24.6.0",
    "env": "development"
  },
  "packageManager": {
    "name": "bun",
    "version": "1.3.10"
  },
  "frameworks": [
    {
      "name": "svelte",
      "version": "^5.53.11"
    },
    {
      "name": "@sveltejs/kit",
      "version": "^2.55.0"
    }
  ],
  "databases": null,
  "betterAuth": {
    "version": "1.5.3",
    "config": null
  }
}

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

Backend

Auth config (if applicable)

import {
	type AuthFunctions,
	createClient,
	type GenericCtx,
} from '@convex-dev/better-auth'
import { convex } from '@convex-dev/better-auth/plugins'
import { type BetterAuthOptions, betterAuth } from 'better-auth/minimal'
import { admin, anonymous } from 'better-auth/plugins'
import { components, internal } from './_generated/api'
import type { DataModel } from './_generated/dataModel'
import authConfig from './auth.config'
import authSchema from './betterAuth/schema'

const siteUrl = process.env.SITE_URL

const authFunctions: AuthFunctions = internal.auth

export const authComponent = createClient<DataModel, typeof authSchema>(
	components.betterAuth,
	{
		authFunctions,
		local: {
			schema: authSchema,
		},
		triggers: {
			user: {
				onCreate: async (ctx, doc) => {
					await ctx.db.insert('users', { authId: doc._id })
				},
				onDelete: async (ctx, doc) => {
					const user = await ctx.db
						.query('users')
						.withIndex('authId', (q) => q.eq('authId', doc._id))
						.first()

					if (user) {
						await ctx.db.patch(user._id, { deletedAt: Date.now() })
					}
				},
			},
		},
	},
)

export const { onCreate, onUpdate, onDelete } = authComponent.triggersApi()

export const createAuthOptions = (ctx: GenericCtx<DataModel>) => {
	return {
		rateLimit: {
			enabled: true,
		},
		baseURL: siteUrl,
		database: authComponent.adapter(ctx),
		emailAndPassword: {
			enabled: true,
			requireEmailVerification: false,
		},
		plugins: [
			convex({ authConfig }),
			admin(),
			anonymous(),
		],
	} satisfies BetterAuthOptions
}

export const createAuth = (ctx: GenericCtx<DataModel>) => {
	return betterAuth(createAuthOptions(ctx))
}

Additional context

I'm using better-auth via Convex. In Convex's runtime environment, the getIp function fails to resolve the client IP address for two reasons:

  1. Header-based resolution fails: Convex does not pass standard headers like x-forwarded-for in the request, so the header lookup loop yields no result.
  2. Localhost fallback is not triggered: The fallback to LOCALHOST_IP (127.0.0.1) relies on isTest() or isDevelopment() returning true. However, Convex's runtime does not set NODE_ENV (or whichever environment variable these checks rely on) in a way that better-auth recognizes, so the fallback is skipped entirely.

As a result, getIp returns null, rate limiting is skipped, and the warning message is logged — which, as noted above, incorrectly references a nonexistent trustedProxies option.

Originally created by @ic4l4s9c on GitHub (Mar 15, 2026). Original GitHub issue: https://github.com/better-auth/better-auth/issues/8615 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce The reproduction steps should not really matter since the issue is not with me seeing the warning message, but with incorrect/confusing content. ### Current vs. Expected behavior Current behavior: ``` WARN [Better Auth]: Rate limiting skipped: could not determine client IP address. If you're behind a reverse proxy, make sure to configure `trustedProxies` in your auth config.' ``` The problem is there is no `trustedProxies` option anywhere in `better-auth`; the only place it's mentioned is #8006. Expected behavior: The warning message should align with the documentation and mention either [`trustedProxyHeaders`](https://better-auth.com/docs/reference/security#trusted-proxy-headers) or [`trustedOrigins`](https://better-auth.com/docs/reference/security#trusted-origins) or other relevant config options (that can be found in the docs). ### What version of Better Auth are you using? 1.5.3 ### System info ```bash { "system": { "platform": "linux", "arch": "x64", "version": "#1 SMP PREEMPT_DYNAMIC Mon, 09 Feb 2026 17:16:33 +0000", "release": "6.18.9-arch1-2", "cpuCount": 32, "cpuModel": "AMD Ryzen 9 9950X3D 16-Core Processor", "totalMemory": "186.34 GB", "freeMemory": "147.53 GB" }, "node": { "version": "v24.6.0", "env": "development" }, "packageManager": { "name": "bun", "version": "1.3.10" }, "frameworks": [ { "name": "svelte", "version": "^5.53.11" }, { "name": "@sveltejs/kit", "version": "^2.55.0" } ], "databases": null, "betterAuth": { "version": "1.5.3", "config": null } } ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript import { type AuthFunctions, createClient, type GenericCtx, } from '@convex-dev/better-auth' import { convex } from '@convex-dev/better-auth/plugins' import { type BetterAuthOptions, betterAuth } from 'better-auth/minimal' import { admin, anonymous } from 'better-auth/plugins' import { components, internal } from './_generated/api' import type { DataModel } from './_generated/dataModel' import authConfig from './auth.config' import authSchema from './betterAuth/schema' const siteUrl = process.env.SITE_URL const authFunctions: AuthFunctions = internal.auth export const authComponent = createClient<DataModel, typeof authSchema>( components.betterAuth, { authFunctions, local: { schema: authSchema, }, triggers: { user: { onCreate: async (ctx, doc) => { await ctx.db.insert('users', { authId: doc._id }) }, onDelete: async (ctx, doc) => { const user = await ctx.db .query('users') .withIndex('authId', (q) => q.eq('authId', doc._id)) .first() if (user) { await ctx.db.patch(user._id, { deletedAt: Date.now() }) } }, }, }, }, ) export const { onCreate, onUpdate, onDelete } = authComponent.triggersApi() export const createAuthOptions = (ctx: GenericCtx<DataModel>) => { return { rateLimit: { enabled: true, }, baseURL: siteUrl, database: authComponent.adapter(ctx), emailAndPassword: { enabled: true, requireEmailVerification: false, }, plugins: [ convex({ authConfig }), admin(), anonymous(), ], } satisfies BetterAuthOptions } export const createAuth = (ctx: GenericCtx<DataModel>) => { return betterAuth(createAuthOptions(ctx)) } ``` ### Additional context I'm using `better-auth` via [Convex](https://www.convex.dev/). In Convex's runtime environment, the `getIp` function fails to resolve the client IP address for two reasons: 1. **Header-based resolution fails:** Convex does not pass standard headers like `x-forwarded-for` in the request, so the header lookup loop yields no result. 2. **Localhost fallback is not triggered:** The fallback to `LOCALHOST_IP` (`127.0.0.1`) relies on `isTest()` or `isDevelopment()` returning `true`. However, Convex's runtime does not set `NODE_ENV` (or whichever environment variable these checks rely on) in a way that `better-auth` recognizes, so the fallback is skipped entirely. As a result, `getIp` returns `null`, rate limiting is skipped, and the warning message is logged — which, as noted above, incorrectly references a nonexistent `trustedProxies` option.
GiteaMirror added the locked label 2026-04-13 07:30:20 -05:00
Author
Owner

@github-actions[bot] commented on GitHub (Mar 31, 2026):

This issue has been locked as it was closed more than 7 days ago. If you're experiencing a similar problem or you have additional context, please open a new issue and reference this one.

<!-- gh-comment-id:4165917645 --> @github-actions[bot] commented on GitHub (Mar 31, 2026): This issue has been locked as it was closed more than 7 days ago. If you're experiencing a similar problem or you have additional context, please open a new issue and reference this one.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#11136