API reference

withAssertion() reference

A middleware wrapper that handles assertion extraction, verification, counter updates, and error responses.


Signature

function withAssertion(
  options: WithAssertionOptions,
  handler: (
    req: Request,
    context: AssertionContext,
  ) => Response | Promise<Response>,
): (req: Request) => Promise<Response>

Options

FieldTypeRequiredDescription
appIdstringYesYour Team ID + bundle ID (e.g., "TEAMID1234.com.example.app").
developmentEnvbooleanNoDefault false. Set true for development AAGUID.
getDeviceKey(deviceId: string) => Promise<DeviceKey | null>YesFetch the device's stored public key and counter. Return null if not found.
updateSignCount(deviceId: string, newSignCount: number) => Promise<void>YesPersist the updated counter after successful verification.
extractAssertionExtractAssertionFnNoCustom extraction logic. Default reads from standard headers.
onError(error: AssertionError, req: Request) => Response | Promise<Response>NoCustom error response handler.

Types

DeviceKey

type DeviceKey = {
  publicKeyPem: string
  signCount: number
}

AssertionContext

Passed to your handler after successful verification:

type AssertionContext = {
  deviceId: string // The device identifier from extraction
  signCount: number // The new counter value (already persisted)
  rawBody: Uint8Array // The raw request body bytes
}

Constants

const DEFAULT_ASSERTION_HEADER = 'X-App-Attest-Assertion'
const DEFAULT_DEVICE_ID_HEADER = 'X-App-Attest-Device-Id'

The default extractor reads the assertion from X-App-Attest-Assertion and the device ID from X-App-Attest-Device-Id. Both are importable constants.


Default error responses

When verification fails and no onError is provided:

Error codeHTTP statusResponse body
INVALID_FORMAT400{ "error": "...", "code": "INVALID_FORMAT" }
DEVICE_NOT_FOUND401{ "error": "Device not found", "code": "DEVICE_NOT_FOUND" }
RP_ID_MISMATCH401{ "error": "...", "code": "RP_ID_MISMATCH" }
COUNTER_NOT_INCREMENTED401{ "error": "...", "code": "COUNTER_NOT_INCREMENTED" }
SIGNATURE_INVALID401{ "error": "...", "code": "SIGNATURE_INVALID" }
INTERNAL_ERROR500{ "error": "...", "code": "INTERNAL_ERROR" }

Handler behavior

  • Your handler only runs after successful verification and counter update.
  • Errors thrown by getDeviceKey or updateSignCount are wrapped as INTERNAL_ERROR.
  • Errors thrown by your handler are not caught — they propagate normally.

Import path: @bradford-tech/supabase-integrity-attest or @bradford-tech/supabase-integrity-attest/assertion

For usage examples, see The withAssertion wrapper guide.

Previous
verifyAssertion()