Address claude-review round 1 on #919:
- Security: userinfo responses carry no `exp`, so userinfo-validated opaque
tokens were cached for the 1h default TTL — a revoked/expired token could be
honored for up to an hour. Cache them for `userinfo_cache_ttl` (5 min)
instead, and document the bounded-staleness window in the docstring.
- Metrics: when introspection AND userinfo both fail, record
("introspect","invalid") + ("userinfo","invalid") separately and set
validation_method="userinfo" before the userinfo call so a userinfo
exception caught by the outer handler is attributed correctly.
- Style: use the hasattr(...) + truthy pattern for userinfo_uri, matching the
introspection block above it.
- Tests: cache-hit allowlist bypass for via-userinfo tokens; short-TTL
assertion; userinfo timeout / connect-error / malformed-JSON fail-closed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>