Skip to content

Expose Management API rate limit info via a client callback - #774

Open
ProdigyTom wants to merge 3 commits into
auth0:masterfrom
ProdigyTom:feat/expose-rate-limit-data
Open

ProdigyTom wants to merge 3 commits into
auth0:masterfrom
ProdigyTom:feat/expose-rate-limit-data

Conversation

@ProdigyTom

@ProdigyTom ProdigyTom commented Jul 27, 2026 •

Copy link
Copy Markdown

Changes

Exposes Auth0's rate-limit information (x-ratelimit-limit / -remaining / -reset) from every Management and Authentication API response, via an opt-in handler, so callers can monitor how close they are to the limit (the ask in #606).

  • Auth0::Internal::Http::RateLimit — value object (limit, remaining as Integers; reset as a UTC Time). Blank/non-numeric header values become nil (never a misleading 0). Two builders: from_http_response (Management/RawClient, Net::HTTP) and from_headers (Authentication/HTTPProxy, RestClient).
  • rate_limit_handler option on Auth0::Client, invoked with the parsed RateLimit after every response on both API paths.
  • Every response is reported, including the 429s that trigger an automatic retry, so a handler watching remaining sees the point where it ran out.
  • Non-breaking: the return value of API calls is unchanged. A handler error is caught and warned (so broken monitoring is visible) but never breaks a request.
  • Management wiring attaches the handler to the generated client's raw client and raises if it can't (so a future internals change fails loudly rather than silently disabling the feature).
  • All changes live in fernignored files (lib/auth0/internal/**, lib/auth0/mixins/**, lib/auth0/auth_client.rb), so they survive regeneration.
  • README + EXAMPLES documentation and unit tests (value object, retried-request notification, token-rebuild re-attach, Authentication path, client wiring).
client = Auth0::Client.new(
  domain: ENV["AUTH0_DOMAIN"],
  client_id: ENV["AUTH0_CLIENT_ID"],
  client_secret: ENV["AUTH0_CLIENT_SECRET"],
  rate_limit_handler: ->(rl) { StatsD.gauge("auth0.rate_limit.remaining", rl.remaining) if rl.remaining }
)
client.users.get(id: "auth0|123") # handler fires with the response's rate limit

References

Testing

Unit tests under test/unit/ cover header parsing (symbol/dashed/mixed-case keys, 0 vs blank/non-numeric, reset + whitespace), notification on every response across a retried request, the handler error being swallowed, the Authentication-API path, and the client wiring (including re-attach after a token-triggered rebuild). Full rake test passes locally with no failures.

  • This change adds unit test coverage
  • This change adds integration test coverage
  • This change has been tested on the latest version of Ruby

Checklist

  • I have read the Auth0 general contribution guidelines
  • I have read the Auth0 Code of Conduct
  • All existing and new tests complete without errors
  • Rubocop passes on all added/modified files
  • All active GitHub checks have passed

@ProdigyTom
ProdigyTom requested a review from a team as a code owner July 27, 2026 18:57
@kishore7snehil

Copy link
Copy Markdown
Contributor

@ProdigyTom I can see some merge conflicts. Can you please resolve them? Post that I can take a look

@ProdigyTom
ProdigyTom force-pushed the feat/expose-rate-limit-data branch from 1943366 to f119645 Compare September 2, 2026 13:39
@ProdigyTom ProdigyTom changed the title Expose rate limit data via optional block on API responses Expose Management API rate limit info via a client callback Sep 2, 2026
@ProdigyTom

Copy link
Copy Markdown
Author

@kishore7snehil my original change was against v5 and after the change to v6 I wasn't really able to resolve my merge conflicts in a way that still solved our problem. The rate limiting information gets dropped earlier in some generated code. So I wound up going a slightly different direction. let me know if it makes sense

Exposes Auth0's rate limit info (x-ratelimit-limit / -remaining / -reset) from
every Management API response via an opt-in callback, so callers can monitor how
close they are to the limit (per auth0#606).

- Add Auth0::Internal::Http::RateLimit (limit/remaining/reset; blank and
  non-numeric header values become nil rather than 0)
- RawClient gains a rate_limit_handler, invoked in #send after retries on every
  response; handler errors are swallowed so they can't break a request. #send's
  return value is unchanged, so generated callers are unaffected.
- Wire it through the custom client: Auth0::Client.new(management_rate_limit_handler:)
  attaches the handler to the management raw client
- Unit tests for RateLimit, RawClient#send handler behavior, and client wiring

All changes live in fernignored files, so they survive regeneration. Refs auth0#606.
@ProdigyTom
ProdigyTom force-pushed the feat/expose-rate-limit-data branch from f119645 to df19130 Compare September 23, 2026 20:35
Comment thread lib/auth0/auth_client.rb
def attach_rate_limit_handler(management)
return if @management_rate_limit_handler.nil?

raw_client = management.instance_variable_get(:@raw_client)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reaches into the generated Management client for its @raw_client by instance variable, and the if raw_client means that if a future regeneration renames or restructures that variable, the handler just never gets attached and the feature goes quiet with no error anywhere. This file is kept across regeneration but the generated class it reaches into is not, so the two can drift apart and nothing would flag it.

We should be handling this carefully.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have made this raise a Auth0::Unsupported error for now so that a future internals change surfaces immediately instead of silently skipping.

I'm using the ivar because the generated Auth0::Management doesn't expose its raw client, and since that class is regenerated, we can't add an accessor from our side without it being clobbered. If you'd be open to exposing a public reader for the raw client on the generated Management class, I would switch to it and drop the instance_variable_get entirely.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A public reader on Auth0::Management would be the cleaner fix, but that class is generated, so a hand edit would be overwritten on the next regen. It would need to come from the Fern side, so not blocking this PR on it.

The respond_to? check with the raise is enough for now, since a rename would fail loudly instead of silently dropping the handler.

One small question on the error. Auth0::Unsupported is part of the HTTP error family, and this isn't an HTTP failure. Would a plain Auth0::Exception fit better here?

Comment thread lib/auth0/internal/http/raw_client.rb Outdated
Comment thread lib/auth0/internal/http/raw_client.rb Outdated
Comment thread test/unit/internal/http/test_raw_client.rb Outdated
Comment thread test/unit/test_auth_client_rate_limit.rb Outdated
Comment thread lib/auth0/internal/http/rate_limit.rb Outdated
Comment thread test/unit/internal/http/test_rate_limit.rb Outdated
Comment thread test/unit/internal/http/test_rate_limit.rb Outdated
Comment thread lib/auth0/mixins/initializer.rb Outdated
Comment thread lib/auth0/mixins/initializer.rb Outdated
- Notify on every response (inside the retry loop) so intermediate 429s reach
  the handler, not just the final response
- Fail loud if the handler can't be attached to the management raw client
  (raise) instead of silently no-opping if internals drift
- Warn (but still swallow) when a handler raises, so broken monitoring is visible
- Extend support to the Authentication API path (HTTPProxy), via a single
  rate_limit_handler option covering both APIs
- RateLimit gains from_http_response (Net::HTTP) and from_headers (RestClient)
  builders; reset/whitespace parsing pinned
- Tests: retried-request notification, token-rebuild re-attach, case-insensitive
  header lookup, reset garbage/whitespace, Authentication-path handler
- Docs: README options row + Rate Limit Monitoring section, EXAMPLES snippet

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants