Functions
SharedSecretOptions
Alias of ::ai::agent::auth/BearerOptions
Shared-secret bearer-token verification configuration. Not
integrated with Hot API keys — for that, use PlatformOptions and
verify-platform. Use this only for:
- Self-hosted agents not running on the Hot platform.
- Webhook endpoints with
auth_mode = "none"where the upstream can still sendAuthorization: Bearer <token>. - Local dev, staging allowlists, and
dev-driverruns.
Either token-env or token must be set; header defaults to
authorization. The helper accepts both Bearer <token> and
bare-token header values so it works whether or not the caller
sent the standard prefix.
anonymous
fn (): Verifier
Build a Verifier that always succeeds. Use only when you
intentionally want to allow unauthenticated traffic — typically
demos and local dev. Production webhooks should never accept this.
fail-result
fn (msg: Str): AuthResult
header-lookup
fn (headers: Map?, name: Str): Str?
Internal: case-insensitive header lookup; returns null if missing or empty.
hmac-verifier
fn (opts: HmacOptions): Verifier
Build a Verifier for an HMAC-signed body. See HmacOptions.
ns
Alias of ::ai::agent::auth/
Webhook authentication helpers for agent transport adapters.
Three complementary mechanisms are supported, designed to compose:
- Platform — assert that the Hot platform itself authenticated
the caller. When the webhook endpoint has
auth_mode = "required", Hot validatesAuthorization: Bearer <hot_api_key>against the org/env API keys and threads anauthmap onto theHttpRequest.verify-platformreads that map. This is the canonical choice for any production webhook deployed on Hot. - HMAC — verify a raw-body HMAC-SHA256 signature in a header (Slack, Stripe, GitHub, Telegram secret-token+IP, custom). The only option for third-party webhooks where the upstream cannot send a Hot API key.
- Shared secret — verify a static
Authorization: Bearer <token>(or any header) against an env-resolved secret. Useful for self-hosted agents,auth_mode = "none"endpoints, and local dev. Not integrated with Hot API keys — that is whatverify-platformis for.
All helpers are pure; secrets are read from the environment via
::hot::env.
Typical use, deny-by-default
Wrap your webhook handler with protect:
::auth ::ai::agent::auth
fn meta {webhook: {…}} (request) {
::auth/protect(request, [
::auth/platform-verifier(),
::auth/hmac-verifier(::auth/HmacOptions({
secret-env: "TEAMAGENT_WEBHOOK_SECRET",
header: "x-hot-signature",
scheme: "sha256=",
})),
], handle-message)
}
protect runs the verifiers in order, returning the first
successful auth or a 401 if none succeed. Empty verifier list
yields 401, so forgetting to configure auth fails closed rather
than open.
Demos that intentionally allow unauthenticated traffic pass an
explicit [::auth/anonymous()] verifier list.
ok-result
fn (): AuthResult
platform-verifier
fn (): Verifier
fn (opts: PlatformOptions): Verifier
Build a Verifier for the platform-auth check. Call with no args
to accept any authenticated caller, or with PlatformOptions to
constrain by type / service-key id.
::auth/platform-verifier()
::auth/platform-verifier(::auth/PlatformOptions({
require-types: ["api-key", "service-key"],
}))
protect
fn (request: Any, verifiers: Vec, handler: Fn): Any
Deny-by-default webhook middleware. Runs verifiers against
request; if auth succeeds, calls handler(request); otherwise
returns a 401 HttpResponse with unauthorized(reason).
fn meta {webhook: {service: "team-agent", path: "/web", method: "POST"}}
(request: HttpRequest): HttpResponse {
::auth/protect(request, [
::auth/platform-verifier(),
::auth/hmac-verifier(::auth/HmacOptions({
secret-env: "TEAMAGENT_HMAC_SECRET",
header: "x-hot-signature",
scheme: "sha256=",
})),
], handle-message)
}
Empty verifiers returns 401 with no-verifiers. Demos can opt
out by passing [::auth/anonymous()].
resolve-secret
fn (literal: Str?, env-name: Str?): Str?
Internal: resolve a literal-or-env secret. Returns null when
neither field is set; returns the env value when only
secret-env is set.
run-verifier
fn (request: Any, body: Str, verifier: Verifier): AuthResult
Internal: dispatch a single Verifier against a request.
shared-secret-verifier
fn (opts: BearerOptions): Verifier
Build a Verifier for a shared-secret bearer token. See BearerOptions.
strip-prefix
fn (s: Str, prefix: Str?): Str
Internal: remove prefix from the start of s if present, otherwise return s unchanged.
unauthorized
fn (reason: Str?): ::hot::http/HttpResponse
Build a 401 HttpResponse with a JSON body. reason is included so
callers can correlate failures in logs without leaking secrets.
verify
fn (request: Any, verifiers: Vec): AuthResult
Run verifiers against request in order, returning the first
ok result or the last failure if none succeed.
request is the HttpRequest value passed to a webhook handler.
The raw body is read from request.body-raw (set by the platform
on webhook requests) — HMAC signatures will not match against a
re-serialized JSON body.
An empty verifiers list returns fail-result("no-verifiers"),
which protect translates into a 401. Auth fails closed.
verify-any
fn (headers: Map?, body: Str, candidates: Vec
Try multiple verifiers in order, returning the first ok result or
the last failure if none succeed. Useful when a webhook
endpoint accepts either an HMAC signature OR a shared-secret
bearer token. For platform-issued API keys, use verify with
platform-verifier() so the full request auth context is available.
Each entry is {kind, options} where kind is one of:
"hmac"(options:HmacOptions)"shared-secret"(options:BearerOptions)
Prefer verify (which takes a full HttpRequest and a
Vec<Verifier>) for new code.
verify-hmac
fn (headers: Map?, body: Str, opts: HmacOptions): AuthResult
Verify an HMAC-signed webhook body. headers and body come from
the transport's parsed request; body should be the raw, undecoded
body string the provider used to sign — re-serializing JSON will
break the signature.
Returns an AuthResult. On failure, error is safe to log and
surface to the caller.
Failure reasons:
secret-not-set— neithersecretnorsecret-envresolved.signature-missing— the signature header was absent or empty.timestamp-stale—timestamp-headerwas older thanmax-skew-seconds.signature-mismatch— HMAC did not match.
verify-platform
fn (request: Any, opts: PlatformOptions): AuthResult
Verify that the Hot platform authenticated the inbound webhook
request. The platform sets request.auth = {type, …} when the
endpoint is configured with auth_mode = "required". Returns:
okifrequest.authis present and (whenrequire-typesis set) theauth.typeis in the allowlist, and (whenrequire-service-key-idis set) the service-key id matches.
Failure reasons:
platform-auth-missingplatform-auth-type-rejected:<type>platform-auth-service-key-id-mismatch
This is a structural check — the platform has already validated
the credential against the database. We only inspect the
already-trusted auth map.
verify-shared-secret
fn (headers: Map?, opts: BearerOptions): AuthResult
Verify a shared-secret bearer-token header. Accepts either
Bearer <token> or a bare <token> value, so it works whether or
not the caller sent the standard scheme prefix. The header name
defaults to authorization.
This is not a Hot API key check — see BearerOptions for when
to reach for this helper vs. verify-platform.
Returns an AuthResult. On failure, error is one of:
token-not-settoken-missingtoken-mismatch
Types
AuthResult
AuthResult type {
ok: Bool,
error: Str?
}
Outcome of a verification call. ok is true on success;
error carries a human-readable reason on failure (no secret
material). Pass error straight to the transport's unauthorized
helper to produce a 401 response.
BearerOptions
BearerOptions type {
token-env: Str?,
token: Str?,
header: Str?
}
Shared-secret bearer-token verification configuration. Not
integrated with Hot API keys — for that, use PlatformOptions and
verify-platform. Use this only for:
- Self-hosted agents not running on the Hot platform.
- Webhook endpoints with
auth_mode = "none"where the upstream can still sendAuthorization: Bearer <token>. - Local dev, staging allowlists, and
dev-driverruns.
Either token-env or token must be set; header defaults to
authorization. The helper accepts both Bearer <token> and
bare-token header values so it works whether or not the caller
sent the standard prefix.
HmacOptions
HmacOptions type {
secret-env: Str?,
secret: Str?,
header: Str,
scheme: Str?,
algorithm: Str?,
prefix-body: Str?,
timestamp-header: Str?,
max-skew-seconds: Int?
}
HMAC verification configuration.
secret-env— environment variable holding the shared secret.secret— literal secret (rare; prefersecret-env).header— case-insensitive header name carrying the signature.scheme— optional prefix on the header value (e.g."sha256=","v0="). The prefix is stripped before comparison.algorithm—"sha256"(default),"sha512", or"sha1".prefix-body— optional string prepended to the body before hashing. Some providers (Slack v0) sign"v0:<timestamp>:<body>"; pass that prefix here.timestamp-header— optional header providing the request timestamp; required whenmax-skew-secondsis set.max-skew-seconds— when set, reject signatures whosetimestamp-headeris more than this many seconds away from now. Mitigates replay attacks.
PlatformOptions
PlatformOptions type {
require-types: Vec?,
require-service-key-id: Str?
}
Platform-auth verification configuration. Reads the auth map
that Hot's API server adds to the inbound HttpRequest when the
webhook endpoint is configured with auth_mode = "required".
require-types— when set, the auth context'stypefield ("api-key","session","service-key") must be in this list.nullmeans "any authenticated caller is fine".require-service-key-id— when set, only allow this specific service-key id. Ignored when the auth context isn't a service key.
Verifier
Verifier type {
kind: Str,
options: Any
}
A single auth check. Compose with verify and protect. Build via
one of the constructor helpers below — never construct by hand
unless you want to thread an unknown kind.
kind—"platform","hmac","shared-secret", or"anonymous".options— the typed options for the kind.