> This page is for SDKs, version Legacy.
> For other versions, use one of these documentation indexes:
> - Current (default): https://buildwithfern.com/learn/sdks/current/llms.txt
> - Legacy: https://buildwithfern.com/learn/sdks/legacy/llms.txt

> For clean Markdown content of this page, append .md to this URL. For the complete documentation index, see https://buildwithfern.com/learn/llms.txt.

## 1.19.0

**`(feat):`** Add webhook body-hash binding verification before HMAC signature checks.

**`(fix):`** Fix generated `verify_signature` webhook helper raising instead of returning `false`
when `signature_header` or `signature_key` is an empty string. An empty key was passed
to `OpenSSL::HMAC.digest`, which raises on OpenSSL 3.x; the input guard now fails
closed on empty (not just nil) signature header and key, matching the never-raise
contract.

**`(feat):`** Add webhook signature verification support. When a webhook declares HMAC signature
verification in the IR, the generator now emits a `WebhooksHelper` (plus named
`<WebhookName>WebhooksHelper` overrides for distinct configs) exposing a static
`verify_signature` method, backed by a stdlib-only `Internal::WebhookSignature`
core utility (HMAC via OpenSSL, constant-time comparison). Supports timestamp
tolerance checks, signature prefixes, configurable payload components/delimiter,
and alphabetical body sorting. Asymmetric verification is not emitted.

## 1.18.2

**`(fix):`** Fix a thread-safety bug in the generated `OAuthProvider` and
`InferredAuthProvider`. The token cache is now guarded by a `Mutex` with
double-checked locking, so only one thread refreshes the token under
concurrent load (e.g. multi-threaded servers like Puma or Sidekiq). The
cache-hit path stays lock-free.

## 1.18.1

**`(fix):`** When a client is constructed with both an environment and server URL variables
(e.g. `region`), the generated client now renders the SELECTED environment's URL
template(s) instead of always using the first environment's template. For
multi-host environments, every host's URL is formatted from the selected
environment's templates. An explicitly provided custom base URL or environment
is never overridden.