AbsoluteJS

Audit, Compliance & Webhooks

The SOC 2 / GDPR tail: an append-only audit trail with PII redaction, self-service session management, data export/erasure, field encryption, and signed outbound webhooks.

#Audit Logging

An AuditSink (in-memory or Postgres) receives structured, append-only events from every flow. Redaction runs before any sink sees an event, dropping or pseudonymizing PII while keeping events correlatable.

TS
import {
  auth,
  createNeonAuditSink,
  createAuditRedactor
} from '@absolutejs/auth';

await auth<User>({
  providersConfiguration: {},
  audit: {
    auditStore: createNeonAuditSink(process.env.DATABASE_URL),
    getUserId: (user) => user.sub,
    // PII redaction applied to every event before any sink sees it:
    redact: createAuditRedactor({ hashFields: ['email'], redactIp: true }),
    onAuditEvent: (event) => forwardToSiem(event) // optional extra sink
  }
});

// auth() emits structured, append-only events from every flow: register, login,
// mfa_*, password_reset, sso_login, scim_provision, organization_created,
// role_assigned, webauthn_*, passwordless_login, token_revoked, and more.

#Session Management

Let users list and revoke their own active sessions, and revoke all of a user's sessions on password reset. Requires an authSessionStore that can enumerate sessions.

TS
await auth<User>({
  providersConfiguration: {},
  authSessionStore, // a store that can enumerate sessions (Neon / Redis)
  sessions: { getUserId: (user) => user.sub }
});

// Self-service session management:
GET    /auth/sessions        // list the caller's active sessions
DELETE /auth/sessions/:id    // revoke one the caller owns

// listUserSessions / revokeUserSessions are also exported for password-reset
// "log out everywhere" flows.

#GDPR Compliance

Right to accessSelf-service export route, delegated to your hooks.
Right to erasureSelf-service delete route — erasure also revokes the user's sessions and clears the cookie.
createSecretCipherBinds an AES-GCM key for encrypting sensitive fields at rest.
TS
import { auth, createSecretCipher } from '@absolutejs/auth';

await auth<User>({
  providersConfiguration: {},
  compliance: {
    getUserId: (user) => user.sub,
    exportUserData: ({ user }) => gatherEverything(user), // GDPR Art. 15
    deleteUserData: ({ user }) => anonymizeOrDelete(user) // GDPR Art. 17
  }
});

// Mounts GET /auth/account/export (right to access -> JSON download) and
// DELETE /auth/account (right to erasure: runs your hook, revokes every session
// the user holds, clears the cookie).

// Field encryption at rest, bound to an AES-GCM key (F2):
const cipher = createSecretCipher(process.env.FIELD_KEY);
const stored = await cipher.encrypt(refreshToken);
const plain = await cipher.decrypt(stored);

#Signed Webhooks

Forward every auth event to your endpoints, HMAC-signed with the Standard Webhooks scheme (Svix-compatible).

Delivery is best-effort and per-endpoint isolated, so a dead endpoint never breaks the auth flow.
TS
import { auth, verifyWebhookSignature } from '@absolutejs/auth';

await auth<User>({
  providersConfiguration: {},
  // Configuring webhooks alone turns on event emission and forwards the whole
  // audit taxonomy, HMAC-signed (Standard Webhooks scheme), to each endpoint:
  webhooks: {
    endpoints: [{ url: 'https://hooks.example.com/auth', secret: process.env.WHSEC }],
    onDeliveryError: ({ endpoint, error }) => log(endpoint.url, error)
  }
});

// Verify on the receiving end (Svix-compatible):
const ok = await verifyWebhookSignature({
  headers: request.headers, // webhook-id / webhook-timestamp / webhook-signature
  payload: await request.text(),
  secret: process.env.WHSEC
});