Skip to content

Trust Layer — JWS, Auth, Audit #14

Open

Description

@ggondim

Summary

Implement the optional trust layer that upgrades A2H interactions from lightweight to auditable mode: JWS signing, strong authentication, audit logging, and replay protection.

Tasks

JWS Signing

  • Sign A2H intents: bind intent → context → timestamp into a JWS
  • Sign responses: bind consent/response → intent → timestamp
  • Key management: generate and rotate signing keys
  • Verification endpoint: validate evidence chain

Strong Authentication

  • WebAuthn/Passkey integration for form-based A2H (method 3)
  • OTP fallback (TOTP, SMS)
  • Authentication challenge flow: form presents auth step before allowing response
  • User identity binding: link channel identity to authenticated identity

Audit Logging

  • Structured audit log for all A2H interactions:
    • Intent sent, intent rendered, response received, evidence signed
    • Timestamps, actor IDs, channel metadata
  • Audit log storage via StorageAdapter extension (new collection/table)
  • Audit log query API (GET /api/audit)

Replay Protection

  • Idempotency keys on intents
  • Timestamp validation (reject stale intents)
  • Nonce binding
  • Single-use approval links (mark as consumed after first response)

Acceptance Criteria

  • When trust layer is active, A2H forms require authentication before submission
  • All A2H interactions produce verifiable JWS evidence
  • Audit log records the full decision path: intent → auth → consent → evidence
  • Replay attacks are rejected (expired timestamps, reused nonces, consumed links)
  • When trust layer is off, none of this code runs (zero overhead)

Dependencies

References

Activity

  1. claude commented on Apr 10, 2026

    @claude

    @claude Implement this issue.

    • Base branch: meta/17
    • Target your PR to meta/17
    • Include fixes #14 in the PR body
  2. claude commented on Apr 10, 2026

    @claude

    Claude finished @claude[bot]'s task in 13m 59s —— View job • claude/17-issue-14-20260410-2337 • Create PR ➔


    Implementing Trust Layer — JWS, Auth, Audit

    Tasks:

    • Read CLAUDE.md and explore codebase structure
    • Understand existing A2H forms and Reply Engine code
    • Implement packages/trust package — types, JWS, replay, audit, auth
    • Implement server-side trust integration (audit API, form auth hooks)
    • Write comprehensive tests (37 test cases)
    • Commit and push changes

    What was implemented

    packages/trust — the trust layer library

    JWS Signing (src/jws/index.ts)

    • ES256 (ECDSA P-256 + SHA-256) via Web Crypto API — zero external deps
    • signIntent() — binds A2H intent → context → timestamp → turnId into a JWS compact serialization
    • signResponse() — binds human response → intent nonce (cryptographic chain: intent → response)
    • generateKeyPair(), importPublicKey(), exportPrivateKey() for key management
    • Auto-generated ephemeral key pair if none provided at startup

    Replay Protection (src/replay/index.ts)

    • ReplayGuard: in-memory nonce store with configurable TTL (default: 1h)
    • validateTimestamp(): rejects stale (intent_expired) and future-dated (intent_future) intents
    • checkNonce(): prevents nonce reuse (nonce_reused) — covers idempotency keys + JTI claims
    • prune(): lazy eviction of expired nonces

    Audit Logging (src/audit/)

    • AuditLogger: structured entries covering the full A2H decision path:
      intent_sent → intent_rendered → auth_challenge_issued → auth_challenge_completed → response_received → evidence_signed
    • InMemoryAuditStorage: in-process storage (cap: 10k entries), suitable for dev
    • AuditStorageAdapter interface: pluggable — MongoDB impl wired in the server

    Strong Authentication (src/auth/)

    • TOTP (RFC 6238): HMAC-SHA-1 via Web Crypto, full encodeBase32/decodeBase32 helpers
    • WebAuthn: challenge generation + authenticatorData/clientDataJSON/signature verification
    • AuthChallengeManager: issue + verify challenges for webauthn, totp, sms_otp methods
      • Challenges scoped to a formKey, expire after configurable TTL (default: 5 min)
      • getVerifiedChallenge(): lets the form submission route confirm auth completed

    TrustLayerManager (src/trust-layer.ts)

    • Single entry point that wires all subsystems together
    • TrustLayerManager.create(): async factory, auto-generates keys when not provided
    • enabled: false → all methods throw immediately — zero overhead for lightweight mode
    • signIntent() + signResponse(): full evidence chain signing with audit logging
    • checkReplay(): validates timestamp + nonce, records nonce on success
    • issueAuthChallenge() / verifyAuthChallenge(): full lifecycle with audit logging
    • queryAuditLog(): filter by turnId, threadId, eventType, date range

    Server-side integration

    Audit API (src/app/api/audit/route.ts)

    • GET /api/audit — query audit log with filters: turnId, threadId, channelId, eventType, fromDate, toDate, limit, offset
    • Returns 404 when TRUST_LAYER_ENABLED is not set (zero overhead for lightweight mode)

    Form Auth Endpoint (src/app/api/form/[formKey]/auth/route.ts)

    • POST /api/form/:key/auth — issue an auth challenge (returns challengeId, method, challenge, expiresAt)
    • PUT /api/form/:key/auth — verify challenge response (TOTP code or WebAuthn assertion fields)
    • Returns challengeId on success; required for form submission when trust is active

    Form Route Updates (src/app/api/form/[formKey]/route.ts)

    • GET: now returns requiresAuth: true + authMethods when trust is active; emits intent_rendered audit event on first view
    • POST: rejects without verified challengeId when trust active (401); validates challenge is for correct form (prevents cross-form replay); emits response_received audit events

    Trust Service (src/lib/trust-service.ts)

    • Server-wide singleton attached to globalThis (survives Next.js hot-reload)
    • MongoAuditStorage: writes audit entries to audit_log MongoDB collection
    • Config from env: TRUST_LAYER_ENABLED, TRUST_LAYER_ALGORITHM, TRUST_LAYER_TIMESTAMP_TOLERANCE, TRUST_LAYER_NONCE_TTL, WEBAUTHN_RP_ID, TRUST_DEFAULT_AUTH_METHOD

    DB Updates (src/lib/db.ts)

    • saveAuditEntry() / queryAuditLog() helpers for the audit_log collection
    • ensureIndexes() extended with audit_log indexes (id unique, turnId+timestamp, eventType+timestamp, timestamp TTL-friendly)

    |

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions