Skip to main content
Maturity: Limited preview. Registration is operator-run, not self-serve. If npm install returns 401, your token is not authorised yet, so talk to your contact on the team.

Register your application

A relying party (RP) is a record in Array’s public client directory. That directory is the document the Alive app reads at scan time to decide whether to show a consent sheet for you at all. We create the record, and you supply its contents.
  • Display name and optional logo. This is what the consent sheet shows the user. It is registered rather than taken from the request, so an RP cannot choose the words on its own consent sheet.
  • Response endpoint allowlist. Exact-match HTTPS URLs. The device refuses to deliver a response anywhere off this list.
  • At least one presenter signing key. A record with no live key cannot do self-issued sign-in at all, because the device pins your key from the directory and refuses unsigned requests.

Prove the domain and the key

Your response endpoint’s origin must serve a well-known document. It satisfies two challenges at once: that you control the domain, and that you hold the private half of the key you registered.
/.well-known/array-rp.json
Generate the keypair yourself and keep the private half in your own secret store. Array holds the public half only.
The well-known document is read at registration time, not at scan time. The device pins keys from the directory record, so rotating your key means updating the record and not just the document.

Install

Three packages, all scoped to @vibechecklabs on GitHub Packages. The split is structural. array-identity-rp depends on nothing but the wire contract, so verification code cannot reach your browser bundle by accident. Point npm at the registry with a token carrying read:packages:
.npmrc
fastify is an optional peer of array-identity-server, so install it only if you import from the /fastify subpath. The framework-free root works in Express, Hono, or raw Node.
Pin exact versions during preview ("0.3.0", not "^0.3.0"). Several of these packages are still release candidates, and wire shapes can still move.

Configuration and pins

We issue these per environment. Chain configuration differs between dev, staging and testnet, and production is not stood up, so do not copy values between environments.

Two chains, and which one you pin

The protocol runs across two testnets, and they do different jobs.
  • Base Sepolia carries the ArrayProtocol contract. Registrations and connections settle here, and the indexer watches it.
  • Ethereum Sepolia carries ArrayRoots, the contract the signed Merkle roots are posted to. That anchor is what an on-chain verifier reads.
ROOTS_EXPECTED_CHAIN_ID and ROOTS_EXPECTED_CONTRACT_ADDRESS pin the protocol chain and contract, not the roots anchor. The operator signs each feed entry over the chain and contract the roots were derived from, so pinning the anchor instead gives you a provider that never warms and a 503 on every proof-carrying sign-in. The failure is silent in the sense that nothing is misconfigured enough to throw at boot. Configuration
  • clientId: your registered application id.
  • responseEndpoint: the allowlisted HTTPS URL the device posts to.
  • Presenter private key and kid: held by you, never sent to Array.
  • array-identity base URL: the issuer origin, which also serves the client directory.
Verifier pins, required only if you verify membership proofs:
  • ROOTS_FEED_URL, plus an API key with the roots:read scope.
  • ROOTS_OPERATOR_BOOTSTRAP_PUBKEY: the operator key whose signature over a root you accept. This is the single trusted input in the membership path.
  • ROOTS_EXPECTED_CHAIN_ID and ROOTS_EXPECTED_CONTRACT_ADDRESS.
None of the three pins has a default, and that is intentional. A defaulted chain id or bootstrap key gives you a verifier that accepts a root from somewhere else. Rotating the operator key means updating your pin.

Next

With a registered record, a presenter key and your pins, go to the quickstart.