> ## Documentation Index
> Fetch the complete documentation index at: https://docs.array.network/llms.txt
> Use this file to discover all available pages before exploring further.

# Get Access

> Register your relying party, generate a presenter key, install the packages, and collect the pins your verifier needs.

<Note>
  **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.
</Note>

## 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.

```json /.well-known/array-rp.json theme={null}
{
  "client_ids": ["my-rp"],
  "jwks": [
    { "kty": "OKP", "crv": "Ed25519", "kid": "rp-key-1", "x": "…" }
  ]
}
```

Generate the keypair yourself and keep the private half in your own secret
store. Array holds the public half only.

<Warning>
  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.
</Warning>

## Install

Three packages, all scoped to `@vibechecklabs` on GitHub Packages.

| Package | Where it runs | What it does |
| - | - | - |
| `array-identity-rp` | Browser | Builds and renders the request, receives the response. No crypto, no verify. |
| `array-identity-server` | Your backend | Signs requests, verifies tokens, roots provider, nonce store. |
| `array-identity-contract` | Both | The dependency-free wire contract. Types and constants. |

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`:

```ini .npmrc theme={null}
@vibechecklabs:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
```

```bash theme={null}
export GITHUB_TOKEN=ghp_your_token_here

pnpm add @vibechecklabs/array-identity-rp          # browser
pnpm add @vibechecklabs/array-identity-server \
         @vibechecklabs/array-identity-contract    # backend
```

`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.

<Tip>
  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.
</Tip>

## 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`.

<Warning>
  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.
</Warning>

## Next

With a registered record, a presenter key and your pins, go to the
[quickstart](/build/quickstart).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.