createAuthUrl(options)
createAuthUrl(options)Promise<{ url, nonce, sig }>Generates an HMAC-signed redirect URL and a cryptographic nonce. Async — it signs via the Web Crypto API, so it returns a Promise and must be awaited. It performs no network call.
| Option | Type | Required | Description |
|---|---|---|---|
spaceId | string | required | Your Space ID (UUID) from the Helix admin panel. |
state | string | required | Opaque base64 payload echoed back in the callback. |
origin | string | required | The browser origin your app is served from, e.g. https://app.example.com. Helix targets its completion message at exactly this origin, so it must match. Sent as sdk_origin. |
secret | string | required | Shared secret from the Helix admin panel. Used to HMAC-SHA256-sign the URL params — server-side only. |
baseUrl | string | optional | Override Helix portal URL. Defaults to https://capsule.helix.id when omitted. |
env | "sandbox" | "production" | optional | Selects which space config Helix looks up. Defaults to production — leave it unset against capsule.helix.id. |
enrollmentId | string | optional | Enrollment ID from a previous verifyCallback result. Pass it to verify this user against their existing enrollment; omit on their first session to enroll them. |
Returns Promise<{ url: string, nonce: string, sig: string }> — store nonce in the user session and hand url to the browser.
URL signing
The signature covers the canonical query string: every param except sig, sorted by key, joined as key=value pairs with &. That string is HMAC-SHA256'd with secret and appended as sig (64 lowercase hex chars):
/voice-auth?space_id=…&nonce=…&state=…&env=…&sdk_origin=…&sig=<hmac-sha256-hex>Because every other param is covered, changing any of them after signing invalidates sig. Build the URL once, on the server, and pass it through untouched.
verifyAuthUrlSignature(url, secret)
verifyAuthUrlSignature(url, secret)Promise<void>Verifies the sig on an auth URL produced by createAuthUrl. Async. Rebuilds the canonical string from the URL's remaining params and compares in constant time via crypto.subtle.verify. Server-side only — it needs the secret.
import { verifyAuthUrlSignature, InvalidAuthUrlSignatureError } from "@helix-id/node";
try {
await verifyAuthUrlSignature(url, process.env.HELIX_SECRET);
} catch (error) {
if (error instanceof InvalidAuthUrlSignatureError) {
// URL is unsigned or was tampered with — do not redirect the user
}
}Returns Promise<void> — resolves when the signature is valid.
Throws InvalidAuthUrlSignatureError when sig is missing or does not match.
Most integrations never call this: your own server produced the URL, so there is nothing to check. It is there for architectures where the URL crosses a trust boundary between services — a gateway, a BFF, or a queue — and the receiving side wants proof it was not rewritten in transit.
verifyCallback(query, options)
verifyCallback(query, options)Promise<VerifyCallbackResult>Verifies the HMAC-signed callback payload and returns the parsed result. Async — it uses the Web Crypto API, so it returns a Promise and must be awaited. The first argument is the raw callback query, every field a plain string.
| Option | Type | Required | Description |
|---|---|---|---|
nonce | string | required | Nonce returned by createAuthUrl, stored in the session. |
secret | string | required | Shared secret from the Helix admin panel. |
Returns Promise<{ status, statusCode, logId, state, enrollmentId? }> — enrollmentId is present when the space has Voice MFA or Banned List enabled, absent otherwise.
Throws InvalidSignatureError, NonceMismatchError, ExpiredTimestampError, MalformedCallbackError.