Sign In

@decionis/presence-auth

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@decionis/presence-auth

Server-side Presence auth hooks for Auth0, Clerk, Okta, Entra, PingOne, and Supabase: risk-based step-up and assurance that replaces always-on MFA, over the Presence /v1/check API.

latest
Source
npmnpm
Version
0.2.0
Version published
Weekly downloads
42
-89.71%
Maintainers
1
Weekly downloads
 
Created
Source

Presence Auth Hooks

packages/presence-auth (npm: @decionis/presence-auth) is the E-commerce & auth channel from the ecosystem roadmap (docs/27): server-side hooks that gate a login or sensitive action on a Presence disposition — the MFA-replacement motion. It is a thin adapter over POST /v1/check (docs/32); the full contract is docs/37 in the repository.

Model

The sign-in page runs the Presence widget, which mints a browser Session Token. Your auth hook holds the tenant API secret (server-side only), passes that token to POST /v1/check, and enforces the answer:

/v1/checkDecisionAuth outcome
PASSallowLogin proceeds — no second factor
CHALLENGE / STEP_UPstep_upRequire a second factor
DENYdenyBlock the login

It fails closed: a missing token or an unreachable Presence API yields step_up, so an outage hardens login rather than locking users out. Presence decides; the hook only reacts.

Auth0 — post-login Action

// Auth0 Action: store the tenant secret as the PRESENCE_API_SECRET Action Secret.
const { createPresenceAction } = require("@decionis/presence-auth/auth0");

exports.onExecutePostLogin = createPresenceAction({
  apiHost: "https://presence.decionis.com",
  apiSecret: event.secrets.PRESENCE_API_SECRET,
});

createPresenceAction(config) returns an onExecutePostLogin(event, api) handler. It reads the Session Token from event.request.body.presence_token (override with tokenFrom), derives accountAgeDays from event.user.created_at, then drives the Action API: allow returns, deny calls api.access.deny("presence_denied"), and step_up calls api.multifactor.enable(provider) (default "any", override with mfaProvider). A login with no Session Token requires MFA.

Clerk — backend guard

Clerk has no server hook that halts a session mid-flow, so the guard returns a decision your own backend enforces (in clerkMiddleware, a server action, or a route handler after auth()):

import { createPresenceGuard } from "@decionis/presence-auth/clerk";

const guard = createPresenceGuard({
  apiHost: "https://presence.decionis.com",
  apiSecret: process.env.PRESENCE_API_SECRET!,
});

const { decision, requiredProof } = await guard({
  token: formData.get("presence_token")?.toString(),
  intent: "payment.checkout",
  context: { amount: 5000, currency: "USD" },
});
if (decision === "deny") throw new Response("Forbidden", { status: 403 });
if (decision === "step_up") return redirectToStepUp(requiredProof);

Surface

ExportEntryContract
createPresenceAction@decionis/presence-auth/auth0Auth0 onExecutePostLogin(event, api) handler driving allow / deny / MFA
createPresenceGuard@decionis/presence-auth/clerkguard({ token, intent?, context? }) → { decision, disposition, requiredProof? }
createOktaInlineHook@decionis/presence-auth/oktaOkta Token Inline Hook responder: proceed+claim / error deny / step-up
createEntraTokenHook@decionis/presence-auth/entraEntra onTokenIssuanceStart extension: annotate presence_* claims (see below)
createPingOneHook@decionis/presence-auth/pingPingOne DaVinci HTTP-connector decision endpoint { decision, disposition }
PresenceCheckClient@decionis/presence-authProvider-neutral POST /v1/check client (fail-closed) for a bespoke integration
decisionFor@decionis/presence-authDisposition → allow / step_up / deny mapping

Enterprise IdP inline hooks

Beyond the consumer Auth0/Clerk hooks, the package ships inline-hook handlers for the enterprise IdPs (docs/39): the IdP calls a Presence-provided handler during a privileged auth event, and the handler delegates to /v1/check. Each is framework-agnostic ((request) => { status, body }), verifies a configured shared secret, and fails closed:

import { createOktaInlineHook } from "@decionis/presence-auth/okta";

const hook = createOktaInlineHook({ apiHost, apiSecret: process.env.PRESENCE_API_SECRET!, secret });
const { status, body } = await hook({ headers: req.headers, body: req.body });

Mapping is faithful to each platform: Okta Token Inline Hooks deny via an error (no MFA command, so step-up is deny or annotate); Entra onTokenIssuanceStart can only annotate tokens (presence_verified + presence_disposition claims — Conditional Access blocks); PingOne returns a decision a DaVinci flow branches on. Distinct from the platform-side Okta connector (docs/17), which runs inside Presence.

Boundaries

The tenant secret is server-side only — never shipped to a browser; the browser holds just the short-lived Session Token. The disposition is authoritative and computed by the Presence API from adverse-only evidence, so a fabricated "clean" client gains nothing. check fails closed on transport error, non-2xx, malformed body, unrecognized disposition, or timeout (timeoutMs, default 4s).

Verification

Vitest (Node), against mocked fetch: pnpm --filter @decionis/presence-auth test — request shape and tenant-secret header, every disposition, all fail-closed paths (including abort), the Auth0 Action outcomes, the Clerk guard's decision mapping, and each IdP inline hook (bad-secret 401, per-provider response mapping, fail-closed missing token).

Distribution

Lockstep 0.x npm line (docs/23) with subpath exports (., ./auth0, ./clerk, ./okta, ./entra, ./ping) and no runtime dependencies — Node's global fetch only. Consumer Shopify/Firebase listings and the enterprise Salesforce/ServiceNow plugins are the planned follow-on for these channels.

FAQs

Package last updated on 10 Aug 2026

Related posts