Context
0.5.0's request restrictions deliberately do NOT touch last_used_at on a refused request: usage stats run only on auth success, so refused traffic can never masquerade as a working integration (downstream, vehiclesdb-web's onboarding detects "first request" via last_used_at, and a refused curl must not tick it).
Commit 8d83c30 closed the attribution half: the after_authentication callback context now carries api_key_id on every identified-but-refused request (environment isolation, origin/IP restrictions), matching what scope refusals always did. Host apps can now count refusals per key.
The open design question
Callbacks are a primitive, not an affordance. From the bundled dashboard, a key that is being actively used and refused (misconfigured origin lock, wrong environment) still looks identical to a key nobody ever tried: last_used_at nil, requests_count 0. That is a support-ticket generator: "my key does not work" with nothing on the key's page to say "requests ARE arriving and being refused, most recently at X, because Y".
Options considered:
last_refused_at (+ maybe refusals_count, last_refusal_code) columns, stamped through the same async stats-job path on identified refusals. Dashboard shows "last refused N minutes ago: origin_not_allowed" on the key page. Clean semantics; costs a migration and widens the stats write path.
- Callback-only (status quo after 8d83c30): document a recipe; each host app builds its own. Zero gem surface, but every host repeats the work and the bundled dashboard stays blind.
- Stamp
last_used_at on refusals: rejected. It muddies "used", and breaks any downstream integration-detection built on it (see above).
Leaning toward (1) for a post-0.5.0 minor: it is the same shape as the existing stats machinery, and the dashboard line ("requests are arriving but refused since X") is the actual support-ticket killer.
Not a 0.5.0 blocker; filing so the design decision does not evaporate.
Context
0.5.0's request restrictions deliberately do NOT touch
last_used_aton a refused request: usage stats run only on auth success, so refused traffic can never masquerade as a working integration (downstream, vehiclesdb-web's onboarding detects "first request" vialast_used_at, and a refused curl must not tick it).Commit 8d83c30 closed the attribution half: the
after_authenticationcallback context now carriesapi_key_idon every identified-but-refused request (environment isolation, origin/IP restrictions), matching what scope refusals always did. Host apps can now count refusals per key.The open design question
Callbacks are a primitive, not an affordance. From the bundled dashboard, a key that is being actively used and refused (misconfigured origin lock, wrong environment) still looks identical to a key nobody ever tried:
last_used_atnil,requests_count0. That is a support-ticket generator: "my key does not work" with nothing on the key's page to say "requests ARE arriving and being refused, most recently at X, because Y".Options considered:
last_refused_at(+ mayberefusals_count,last_refusal_code) columns, stamped through the same async stats-job path on identified refusals. Dashboard shows "last refused N minutes ago: origin_not_allowed" on the key page. Clean semantics; costs a migration and widens the stats write path.last_used_aton refusals: rejected. It muddies "used", and breaks any downstream integration-detection built on it (see above).Leaning toward (1) for a post-0.5.0 minor: it is the same shape as the existing stats machinery, and the dashboard line ("requests are arriving but refused since X") is the actual support-ticket killer.
Not a 0.5.0 blocker; filing so the design decision does not evaporate.