Actions

Your code, in the
auth pipeline.

Run your own logic synchronously at every stage of login, registration, and token issuance — to deny, enrich, or transform claims. The Auth0 Actions mental model you already know, native to AuthFI's signed-token path. Bring an HTTPS endpoint, or let us run it sandboxed.

Available on Pro and above. See pricing

The triggers

Hook the moments where a decision is actually made.

An outbound webhook fires after the fact and nobody can block it — by the time it arrives, the token is already signed and in the client's hands. Actions run inside the flow, synchronously, at the four points around token issuance where the verdict still matters: before a session exists, before a user record is created, and on either side of the moment the token is minted.

  • Pre-events gate. A post-login or pre-registration action returns a verdict the runtime honors — the flow blocks, denies, or proceeds on what your code decided.
  • Post-events observe. Once the token is minted, post-issuance work runs out of the critical path — audit, notify, provision — without holding the user.
  • Familiar to Auth0 Actions users. Triggers, an ordered flow, an api object, secrets, deploy and test — native to AuthFI, and synchronous where it counts.
Post-login deny / gate

After the credential check, before a session exists. Run a risk check, require step-up, or deny the sign-in outright.

Pre-registration deny / enrich

Before a new user record is created — federated or direct. Block a disposable domain, enrich the profile, or stop the account from ever existing.

Pre-token issuance transform

After login, before the token is signed. Add, remove, or transform the claims that ride the same signed token as our compliance modules.

Post-token issuance observe

After the token is minted. Notify a downstream system, write an audit record, or kick off provisioning — out of the critical path.

The flow

An ordered flow, on the real pipeline.

Attach actions to a trigger in the order you choose. Each receives an immutable event (user, request, client, connection) and a mutable api. The runtime collects the claim mutations and a single deny/allow verdict, then hands them straight to the token signer — claims flow into the same signed-token path our compliance modules ride, nothing bolted on the side.

Sign-in
login · register · SSO
Your actions run
ordered · synchronous · deny / enrich
action 1action 2action 3
Signed token
claims included
result = { verdict: "allow", claims: { "risk_tier": "low" } }

A deny from any action stops the flow with a real 403 — the user does not sign in and no token is issued. An allow carries the merged claims straight into the signed token.

What it can do

Deny, enrich, transform — synchronously.

An action holds the flow until it returns. That is the line between observing after the fact and actually deciding: block a sign-in, write a claim, or call your own service while the user waits. Claim mutations follow OIDC's rule for custom claims — set under a namespaced URI, merged into the token, never overwriting the registered iss, sub, aud, exp, or iat the signer owns.

  • Deny. Return a typed deny and the flow stops with a real 403 — not a fire-and-forget webhook that everyone ignores. The user does not sign in and no token is issued.
  • Enrich. Pull a tier, a fraud score, or a department from your own system and write it onto the profile or the token at the moment of issuance.
  • Transform claims. Set or remove custom claims on the access token. The same map-merge path our FAPI and SMART modules ride — OIDC-correct, never overwriting iss/sub/aud/exp/iat.
  • Call out. Reach your fraud API, your billing system, or your data warehouse from inside the flow — synchronously, with the result feeding the verdict.
post-login action · block · enrich · claim
exports.onPostLogin = async (event, api) => {
  // 1. block sign-ins from an embargoed country
  if (BLOCKED.has(event.request.geo.country)) {
    return api.access.deny("region_not_allowed");
  }

  // 2. enrich the token from your own fraud API
  const risk = await api.fetch("https://risk.acme.com/score", {
    body: { user: event.user.id, ip: event.request.ip }
  });

  // 3. add a claim that rides the signed token
  api.accessToken.setClaim("https://acme.com/risk", risk.tier);
};

Ten lines. The same event / api shape whether it runs as a signed HTTPS call or managed WASM.

Runtimes

Bring your own, or let us run it.

Two ways to run the exact same action, and you are never forced to migrate. An HTTPS endpoint is a request/response contract over the wire — your code runs anywhere and AuthFI authenticates the call. Managed WASM trades the network hop for an in-process sandbox: a WebAssembly module with no ambient authority, fuel-metered and capability-gated. Start with your own endpoint today; move to WASM when you want zero infra and sub-millisecond execution.

Signed HTTPS endpoint

bring your own runtime
  • Your code runs in your cloud — Lambda, Workers, a container, anywhere.
  • AuthFI signs every request (HMAC + timestamp) so your endpoint can verify it is really us.
  • SSRF-guarded egress, a hard per-call deadline, and HTTPS required.
  • Adopt it today if you already run code — zero new runtime to learn.

Managed in-process WASM

we run it, sandboxed
  • Upload your code; it runs in-process in a sandbox — no network hop, sub-millisecond.
  • No filesystem, no sockets — egress only through an explicit per-action allowlist.
  • Hard fuel, memory, and wall-clock limits: one runaway action can never starve another.
  • Content-addressed and signed — the runtime refuses an unverified or tampered artifact.

The HTTPS tier is permanent — it is the bring-your-own-runtime and call-external-services escape hatch, not a stepping stone we delete.

Test before deploy

Simulate it before it touches a real login.

Custom code on the auth hot path is only safe if you can see what it does before it ships. Run an action against a sample or real event and watch exactly what it would do — the claims it adds, the verdict it returns, the logs it prints, the time it took — without ever issuing a token. Author, version, simulate, deploy, and roll back entirely in the console, before a single real user is affected.

  • No token issued. A dry run exercises the full action against the event but stops short of signing — nothing reaches a client.
  • The diff is the gate. You see the verdict and the exact claims added, so you deploy only when the change looks right.
  • Reversible. Versioned actions roll back to the previous artifact instantly — no redeploy of your stack.
Dry run — post-login ✓ no token issued
Verdict
✓ allow
Duration
44 ms
Claims added
+ added "https://acme.com/risk": "low"
Logs
geo.country=DE — allowed
fetched risk score: tier=low (42ms)

Built for multi-tenant safety

Untrusted code, on the auth hot path — safely.

Running customer code inside token issuance is only acceptable if it can never break the platform — not its latency, not its isolation, not its supply chain. So every guardrail is on by default: the WASM sandbox grants no ambient authority, every artifact is verified before it loads, egress is filtered, and the whole thing is row-level-security scoped per tenant.

Signed artifacts

Every WASM action is content-addressed and signature-verified before it can run — supply-chain integrity by default.

Fuel-limited sandbox

Hard instruction, memory, and wall-clock budgets, plus per-tenant concurrency caps — no tenant can affect another’s auth latency.

SSRF-guarded egress

Tenant-controlled URLs and fetch calls are blocked from reaching internal, link-local, or cloud-metadata addresses.

Tenant-isolated, RLS-backed

Every action, secret, and execution is row-level-security scoped. One tenant’s action can never see another’s event or secrets.

Put your code in the pipeline.

Deny, enrich, and transform claims synchronously at login, registration, and token issuance — with a signed HTTPS endpoint or managed in-process WASM. The Auth0 Actions model you know, native to AuthFI.

Get started

Ready to get started?

Free for 5,000 monthly active users. No credit card required.