npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@bradford-tech/supabase-integrity-attest

v0.3.2

Published

Verify Apple App Attest attestations and assertions using WebCrypto.

Downloads

624

Readme

supabase-integrity-attest

Server-side TypeScript library for verifying Apple App Attest attestations and assertions using the WebCrypto API. Built for Deno and Supabase Edge Functions.

Installation

# Deno
deno add jsr:@bradford-tech/supabase-integrity-attest

# npm
npm install @bradford-tech/supabase-integrity-attest

Subpath imports

If you only need assertion verification, import from the lighter entry point:

// Full library (attestation + assertion)
import { verifyAttestation, verifyAssertion } from "@bradford-tech/supabase-integrity-attest";

// Assertion only — skips asn1js and @noble/curves
import { verifyAssertion } from "@bradford-tech/supabase-integrity-attest/assertion";

// Attestation only
import { verifyAttestation } from "@bradford-tech/supabase-integrity-attest/attestation";

Usage

Attestation (one-time per device)

import { verifyAttestation } from "@bradford-tech/supabase-integrity-attest";

const result = await verifyAttestation(
  { appId: "TEAMID.com.your.bundleid" },
  keyId, // base64 from client
  challenge, // the challenge you issued
  attestation, // base64 CBOR from client
);

// Store result.publicKeyPem and signCount (0) for this device

Protecting edge functions with withAssertion

withAssertion wraps a request handler so that assertion verification, device lookup, and sign count updates happen before your business logic runs.

import { createClient } from "jsr:@supabase/supabase-js@2";
import { withAssertion } from "@bradford-tech/supabase-integrity-attest";

const supabase = createClient(
  Deno.env.get("SUPABASE_URL")!,
  Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!,
);

Deno.serve(withAssertion({
  appId: Deno.env.get("APP_ATTEST_APP_ID")!,
  developmentEnv: Deno.env.get("APP_ATTEST_ENV") === "development",
  getDeviceKey: async (deviceId) => {
    const { data } = await supabase
      .from("device_attestations")
      .select("public_key_pem, sign_count")
      .eq("key_id", deviceId)
      .single();
    return data
      ? { publicKeyPem: data.public_key_pem, signCount: data.sign_count }
      : null;
  },
  updateSignCount: async (deviceId, newSignCount) => {
    await supabase
      .from("device_attestations")
      .update({ sign_count: newSignCount })
      .eq("key_id", deviceId);
  },
}, async (_req, { rawBody }) => {
  const { text, voice } = JSON.parse(new TextDecoder().decode(rawBody));
  // business logic
  return new Response(JSON.stringify({ audio: "..." }), {
    headers: { "Content-Type": "application/json" },
  });
}));

The client sends the assertion and device ID in headers. The request body is the client data that was signed:

POST /functions/v1/your-endpoint
Headers:
  Content-Type: application/json
  X-App-Attest-Assertion: <base64-encoded assertion>
  X-App-Attest-Device-Id: <base64-encoded keyId>
Body:
  {"text": "Hello world", "voice": "en-US"}

Once you have multiple protected functions, extract the shared options into a helper:

// supabase/functions/_shared/attest.ts
import type { WithAssertionOptions } from "@bradford-tech/supabase-integrity-attest";

export const attestOptions: WithAssertionOptions = {
  appId: Deno.env.get("APP_ATTEST_APP_ID")!,
  // ... getDeviceKey, updateSignCount as above
};
// supabase/functions/text-to-speech/index.ts
import { withAssertion } from "@bradford-tech/supabase-integrity-attest";
import { attestOptions } from "../_shared/attest.ts";

Deno.serve(withAssertion(attestOptions, async (_req, { rawBody }) => {
  const { text, voice } = JSON.parse(new TextDecoder().decode(rawBody));
  return new Response(JSON.stringify({ audio: "..." }));
}));

Assertion (low-level)

For full control over the verification flow, use verifyAssertion directly:

import { verifyAssertion } from "@bradford-tech/supabase-integrity-attest";

const result = await verifyAssertion(
  { appId: "TEAMID.com.your.bundleid" },
  assertion, // base64 CBOR from client
  clientData, // the request payload that was signed
  storedPublicKeyPem, // from attestation
  storedSignCount, // last known counter
);

// Update stored signCount to result.signCount

Error handling

import {
  AttestationError,
  AttestationErrorCode,
  AssertionError,
  AssertionErrorCode,
} from "@bradford-tech/supabase-integrity-attest";

try {
  await verifyAttestation(appInfo, keyId, challenge, attestation);
} catch (e) {
  if (e instanceof AttestationError) {
    console.log(e.code); // e.g. "NONCE_MISMATCH", "INVALID_CERTIFICATE_CHAIN"
  }
}

Development environment

For apps using Apple's development App Attest environment:

await verifyAttestation(
  { appId: "TEAMID.com.your.bundleid", developmentEnv: true },
  keyId,
  challenge,
  attestation,
);

Security

See SECURITY.md for vulnerability reporting.

License

MIT