Skip to content

Make MAX_OAUTH_CLIENTS configurable by environment variable #29

Description

@wiverson

Anonymous dynamic client registration is capped at 50 rows (MAX_OAUTH_CLIENTS in src/server/auth.ts). That is a fine default for the intended shape of this product — one person, or a small set of servers — and no change is needed today. Filed so the ceiling is a known decision rather than a surprise.

What the cap does, and why it is not redundant

Two limits guard /oauth2/register, and they bound different things:

  • Better Auth rate limit — 20 per hour. Caps the rate, and resets.
  • MAX_OAUTH_CLIENTS — 50. Caps the total, and does not reset, except that unused clients older than 24h are pruned before the count.

Twenty an hour sustained is still unbounded accumulation — roughly 480 a day — on a volume that also holds the vault, with a 5 GB ceiling on Railway Hobby. The rate limiter only ever asks how fast, never how many.

When 50 might not be enough

  • Many connectors across many clients, each leaving throwaway registrations behind (a failed login leaves one)
  • Someone pointing a fleet at one instance, which the single-user design does not target but does not prevent

The failure mode is self-denial rather than a security hole: once the table is full nobody can register, including the operator adding a legitimate connector. Pruning only helps for clients that are both unused and over a day old, so a burst of throwaways in one afternoon is not immediately recoverable.

Shape of the change

Read an optional override, keeping 50 as the default:

const MAX_OAUTH_CLIENTS = Number(process.env.MAX_OAUTH_CLIENTS) || 50;

Worth deciding at the same time:

  • A sane floor, so a typo cannot set it to 0 and lock out registration entirely
  • Whether the Security tab should show the configured value — it already reports maxOAuthClients via getSecurityPage
  • Whether an operator hitting the cap should see something better than a 429, since the current message does not say the fix is deleting unused connectors

Tests

tests/http/client-cap.test.ts covers the cap and reads MAX_OAUTH_CLIENTS from the module, so it follows an override without editing. Note the trap it documents: testing this over HTTP by looping is meaningless, because Better Auth refuses at 20 with its own "Too many requests" long before the cap of 50 is reached. The test seeds the table directly for that reason.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions