ScalixScalix Docs
Sign up

Pre-Signup Hook

Block or veto account creations from your own backend before the user row exists

Overview

A pre-signup hook is an optional per-project webhook that Scalix POSTs to before every account is created — the parity point for Firebase's blocking functions and Supabase's before user created hook. Use it for domain allowlists, disposable-email rejection, invite-gated signups, or feeding signups into your own fraud pipeline.

While a hook is configured it is fail-closed: a hook that answers non-2xx or that cannot be reached blocks the signup. Projects without a configured hook are never gated.

Configure

bash
curl -X PUT https://api.scalix.world/v1/auth/admin/config \
  -H "Authorization: Bearer $SCALIX_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "pre_signup_hook_url": "https://api.myapp.com/hooks/scalix-signup",
    "pre_signup_hook_secret": "whsec_..."
  }'

pre_signup_hook_url must be https (http is accepted only for localhost, for local testing). An empty string clears the hook. The optional secret signs the body, so your endpoint can verify the caller instead of trusting the URL.

Request

http
POST https://api.myapp.com/hooks/scalix-signup
Content-Type: application/json
X-Scalix-Event: before_user_created
X-Scalix-Signature: sha256=<hex HMAC-SHA256 of the raw body, keyed by pre_signup_hook_secret>
json
{
  "event": "before_user_created",
  "project_id": "uuid",
  "email": "user@example.com",
  "user_metadata": { "plan": "free" }
}

Verify the signature by recomputing the HMAC over the raw request body (do not re-serialize the parsed JSON) and comparing to the header value.

Response

  • 2xx with {"reject": false} or an empty body → the signup proceeds.
  • 2xx with {"reject": true} (or {"decision": "reject"}) → the signup is blocked; the user sees message if provided:
json
{ "reject": true, "message": "Sign-ups are invite-only." }
  • Any non-2xx, timeout, or unreachable host → the signup is blocked (fail-closed).

Notes

  • The hook runs after input validation (email format, password policy, ToS version) but before any row is written — a rejected signup leaves no footprint.
  • It covers email/password signup and first OAuth/OIDC sign-ins (any flow that creates an account). Anonymous sign-in is not gated, matching Firebase's blocking-function scope.
  • Request budget: 1s connect / 3s total, and redirects are not followed — a hook that stalls or redirects blocks the signup rather than extending the request.
  • pre_signup_hook_url must be public https (http only for localhost, for local testing); private, loopback, and link-local addresses are rejected, and the URL is never echoed in error responses.