Skip to content

v0.7.0

Latest

Choose a tag to compare

@github-actions github-actions released this 24 Sep 07:49
· 8 commits to develop since this release
dee5a79

Breaking changes in 0.7.0

This release has ten breaking changes. Two of them (#115 and #139) do not show up as breaking in the PR list below, because their titles have no !. For what each change looks like on the wire and in the logs, see the CHANGELOG.

  • Validation, with CLIENT_ID / CLIENT_SECRET set: a provider 401 to introspection is now 502 Provider Configuration Error, not 401 Invalid Token, and it is logged as validation.provider_config_error (#111). Action: fix the proxy's client credentials, and move alerts off introspect failed.
  • Validation: a provider failure (5xx, 429, another 4xx, an invalid response, a timeout, a network error) is now 502 Bad Gateway. 500 now means only a fault in the proxy itself (#126). Action: review alerts and retry policies keyed on 500. No Retry-After is passed through.
  • Validation: an introspection redirect is refused with 502 Provider Configuration Error (#123). Action: set INTROSPECT_URL to the final URL.
  • Validation: the 401 now carries WWW-Authenticate: Bearer error="invalid_token" (#114). Action: none for a client that ignores the header. If a cross-origin browser client needs to read it, expose the header at your edge.
  • Injection: the session grant no longer follows a redirect. A 3xx gets 502 provider_config_error, and a same-origin 307/308 no longer mints a token (#112). Action: point INJECTION_PROVIDER_ORIGIN at the origin that serves /oauth/token; if the redirect stays on the same origin, the provider or its ingress must answer POST /oauth/token itself, since the origin cannot carry a path. Re-key alerts that matched provider_unavailable / unexpected provider response: 405.
  • Injection: only a 200 counts as a successful session grant. Any other 2xx gets 502 provider_unavailable (#124). Action: none for a provider that follows RFC 6749.
  • Injection: a session grant 401 invalid_client is now 502 provider_config_error, not 401 session_required, and it is logged as injection.provider_config_error at error (#120). Action: fix the INJECTION_CLIENT_ID registration. Alerts on injection.session_unauthorized no longer see this case; alert on injection.provider_config_error.
  • Injection: provider error text that contains a credential is refused at any length, not only from 8 characters up. When the session cookie values or the exchange client secret are shorter than 8 characters and the provider's text contains one, you see the proxy's own wording or invalid_error_code instead of the provider's diagnostic (#115). Action: rotate an INJECTION_EXCHANGE_CLIENT_SECRET that is shorter than 8 characters.
  • Logs, both modes: "x-request-id" is now requestId. Request, decision and failure lines carry an event. A provider 401 about the caller's token now logs at info (validation.token_unauthorized), not error; its message is still introspect failed (#139). Action: move queries from "x-request-id" to requestId, and key alerts on event rather than on level or message.
  • Boot: INTROSPECT_URL must be an absolute http(s) URL without userinfo. A deployment that uses userinfo, a non-URL, or another scheme (such as data:) no longer boots (#140, #141). Action: set the plain endpoint URL, and use CLIENT_ID / CLIENT_SECRET for credentials.

What's Changed

  • test(validation): pin the router's own mappings — pass-through, 400, 401, 500 (#95 F27) by @y1o1 in #96
  • refactor(router): one upstream proxy stage for both modes (#95 F18) by @y1o1 in #97
  • docs: README responsibility maps for the directories that own a contract (#95) by @y1o1 in #98
  • refactor(injection): the session decision out of the middleware, deps injectable (#95 F1, F4) by @y1o1 in #99
  • refactor(injection): the exchange decision out of the handler, its deps injectable (#95 F2) by @y1o1 in #100
  • refactor(validation): the decision out of the handler, its deps injectable (#95 F3) by @y1o1 in #101
  • refactor(validation): the introspection client and the cache out of one function (#95 F5, F23) by @y1o1 in #102
  • refactor(injection): the token-endpoint helpers into a module of their own (#95 F19) by @y1o1 in #103
  • refactor: drop the header field nothing read and the dependency nothing imports (#95 F15, F24) by @y1o1 in #104
  • fix(validation): cancel the introspection body the non-2xx path never reads (#95 F28) by @y1o1 in #105
  • fix(injection): parseJsonBody answers null for the array its type excludes (#95 F34) by @y1o1 in #106
  • fix(injection): report the action a forward without injection actually takes (#95 F31) by @y1o1 in #108
  • refactor(express): extractBearerToken answers the token, not a record of one (#95 F36) by @y1o1 in #110
  • fix(injection): one discriminator for the whole session-error branch (#95 F32) by @y1o1 in #109
  • fix(injection): bound the token response body the success path buffered (#95 F35) by @y1o1 in #107
  • feat(validation)!: a provider 401 that refused the proxy is 502, not 401 (#95 F7) by @y1o1 in #111
  • fix(injection)!: neither token client follows a redirect (#95 F8) by @y1o1 in #112
  • fix(injection): key the session cache by the grant context, not the cookie alone (#95 F33) by @y1o1 in #113
  • fix(injection): redact a credential at any length, not only from eight up (#95 F30) by @y1o1 in #115
  • feat(validation)!: the 401 carries the RFC 6750 challenge it owes (#95 F29) by @y1o1 in #114
  • feat(validation): concurrent misses on one token share one provider call (#95 F6) by @y1o1 in #116
  • feat(proxy): state the cancellation contract, and pin it (#95 F10) by @y1o1 in #117
  • fix(injection): release every provider body the clients answer without reading (#95 F37) by @y1o1 in #118
  • fix(validation): read a 200 introspection body at a bound, not whatever arrives (#95 F39) by @y1o1 in #119
  • fix(injection)!: a session 401 invalid_client is a config error, not an expired session (#95 F47) by @y1o1 in #120
  • fix(injection): an exchange refusal with an undeclared code is still logged (#95 F41) by @y1o1 in #121
  • fix(validation)!: refuse an introspection redirect instead of following it (#95 F43) by @y1o1 in #123
  • fix(injection): strip an empty inbound Authorization like any other (#95 F40) by @y1o1 in #122
  • fix(injection)!: a session grant succeeds on a 200, not on any 2xx (#95 F38) by @y1o1 in #124
  • fix(validation)!: a provider failure is 502, and 500 is the proxy's own (#95 F42) by @y1o1 in #126
  • test(injection): coalescing tests wait for the join, not a duration (#95 F46) by @y1o1 in #125
  • feat(validation): the 400 challenges by what was sent, with an optional realm (#95 F45) by @y1o1 in #127
  • fix(logger): validation's failure lines carry their error (#95 F48) by @y1o1 in #128
  • chore(deps): bump zod from 4.6.2 to 4.6.5 in the production-minor-patch group across 1 directory by @dependabot[bot] in #94
  • chore(deps-dev): bump the dev-dependencies group across 1 directory with 4 updates by @dependabot[bot] in #129
  • docs: every README states its responsibility, carries a date, and cites files not lines by @y1o1 in #131
  • fix(injection): inject checks presence like the other two paths (#133) by @y1o1 in #135
  • docs(router): keep the upstream decorator for header-name casing (#132) by @y1o1 in #136
  • docs: a refused cookie forwards without a minted Authorization, not without any by @y1o1 in #137
  • docs: source-directory READMEs describe the directory; files describe themselves by @y1o1 in #138
  • fix: log requestId and event in both modes, and a caller-caused 401 at info (#134) by @y1o1 in #139
  • fix!: an introspection URL carries no credential, and a raw one is redacted (#140), with the release audit's findings by @y1o1 in #141
  • release: v0.7.0 by @y1o1 in #142

Full Changelog: v0.6.0...v0.7.0