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
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.
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
ArrayProtocolcontract. 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-identitybase URL: the issuer origin, which also serves the client directory.
ROOTS_FEED_URL, plus an API key with theroots:readscope.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_IDandROOTS_EXPECTED_CONTRACT_ADDRESS.