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

# Key Management

Managing private keys securely is the most critical part of any blockchain application. `near-kit` provides several `KeyStore` implementations to suit different environments, from temporary testing to secure production servers.

## 1. `InMemoryKeyStore` (Testing & Scripts)

* **Best for:** Unit tests, CI/CD, and short-lived scripts.

This store keeps keys in a plain JavaScript object in RAM. If the process exits, the keys are gone.

```typescript theme={null}
import { InMemoryKeyStore, Near, parseKey } from "near-kit"

const keyStore = new InMemoryKeyStore()

// You can pre-seed it with keys
await keyStore.add("alice.testnet", parseKey("ed25519:..."))

const near = new Near({
  network: "testnet",
  keyStore: keyStore,
})
```

## 2. `FileKeyStore` (Dev & Servers)

* **Best for:** Local development and simple server deployments.
* **Requires:** Node.js or Bun.

This store reads and writes keys to JSON files in the standard `~/.near-credentials` directory. This makes it compatible with the NEAR CLI.

```typescript theme={null}
import { FileKeyStore } from "near-kit/keys/file";

// Uses ~/.near-credentials/testnet/
const keyStore = new FileKeyStore("~/.near-credentials", "testnet");

const near = new Near({
  network: "testnet",
  keyStore: keyStore
});

// Now you can sign for any account in that folder
await near.transaction("alice.testnet")...
```

## 3. `NativeKeyStore` (Maximum Security)

* **Best for:** Production servers, desktop apps, and CLI tools.
* **Requires:** Node.js/Bun and `@napi-rs/keyring`.

This store uses your operating system's native secure credential storage (Keychain on macOS, Credential Manager on Windows, libsecret on Linux). Keys are encrypted by the OS and protected by the user's password/biometrics.

```bash theme={null}
# Install the native dependency first
npm install @napi-rs/keyring
```

```typescript theme={null}
import { NativeKeyStore } from "near-kit/keys/native"

// Keys are stored in the OS Keychain under "NEAR Credentials"
const keyStore = new NativeKeyStore()

const near = new Near({
  network: "mainnet",
  keyStore,
})

// The first time you add a key, the OS may prompt for permission
await keyStore.add("secure-admin.near", keyPair)
```

> **Note:** OS Keyrings do not allow listing all keys for security reasons. You must know the `accountId` you want to retrieve.

## 4. `RotatingKeyStore` (High Throughput)

* **Best for:** Trading bots, faucets, and high-traffic relayers.

The NEAR network processes transactions sequentially for each Access Key. If you try to send 50 transactions in parallel from one account, most will fail with `InvalidNonce` errors.

`RotatingKeyStore` solves this by managing multiple keys for a single account and rotating through them round-robin.

```typescript theme={null}
import { RotatingKeyStore } from "near-kit"

const keyStore = new RotatingKeyStore({
  "bot.near": ["ed25519:key1...", "ed25519:key2...", "ed25519:key3..."],
})

const near = new Near({ keyStore })

// Now you can fire off concurrent requests!
await Promise.all([
  near.send("a.near", "1 NEAR"),
  near.send("b.near", "1 NEAR"), // Uses Key 2
  near.send("c.near", "1 NEAR"), // Uses Key 3
])
```

<Tip title="Complete Example">
  See [`examples/rotating-keystore.ts`](https://github.com/r-near/near-kit/blob/main/examples/rotating-keystore.ts) for a complete working example including account setup and adding multiple access keys.
</Tip>

## Permissions

When you add a key to an account (using `.addKey`), you define what that key can do.

### Full Access

Can do anything: transfer NEAR, delete the account, deploy code, add more keys.

* **Use case:** Your main admin key.

### Function Call Access

Can **only** call specific methods on a specific contract. It cannot transfer NEAR.

* **Use case:** "Log in with NEAR", limited session keys, automated agents.

```typescript theme={null}
await near
  .transaction("alice.near")
  .addKey(newPublicKey, {
    type: "functionCall",
    receiverId: "game.near",
    methodNames: ["move", "attack"], // Only these methods
    allowance: "0.25 NEAR", // Max gas fees this key can spend
  })
  .send()
```

## Signature schemes

`near-kit` supports three signature schemes. They are interchangeable everywhere a key is used (`parseKey`, `signWith`, `addKey`, the keystores):

| Scheme    | Prefix       | Notes                                                            |
| --------- | ------------ | ---------------------------------------------------------------- |
| Ed25519   | `ed25519:`   | Default. `generateKey()` returns one.                            |
| secp256k1 | `secp256k1:` | Same curve as Ethereum/Bitcoin.                                  |
| ML-DSA-65 | `ml-dsa-65:` | Post-quantum (FIPS 204). Requires nearcore 2.13+ (protocol v85). |

### ML-DSA-65 (post-quantum)

ML-DSA-65 keys let an account sign with a quantum-resistant scheme. Generate one with `MlDsa65KeyPair`, then add it like any other key:

```typescript theme={null}
import { MlDsa65KeyPair, Near } from "near-kit"

const pqKey = MlDsa65KeyPair.fromRandom()

// Add the post-quantum key with an existing full-access key.
await near
  .transaction("alice.near")
  .addKey(pqKey.publicKey.toString(), { type: "fullAccess" })
  .send()

// Then sign transactions with the post-quantum key.
const pqNear = new Near({
  network: "mainnet",
  keyStore: { "alice.near": pqKey.secretKey }, // "ml-dsa-65:<seed>"
})

await pqNear.transaction("alice.near").transfer("bob.near", "1 NEAR").send()
```

For a key generated by `MlDsa65KeyPair`, the serialized secret key is the 32-byte seed (`ml-dsa-65:<base58 seed>`). `parseKey` also accepts the 4032-byte raw expanded secret key that nearcore / near-cli write to credential files (`ml-dsa-65:<base58 raw key>`), so existing credentials load too. Either form round-trips. The public key is 1952 bytes and signatures are 3309 bytes.

#### Deriving from a seed phrase

`parseSeedPhrase` can derive an ML-DSA-65 key from a BIP-39 mnemonic, so a post-quantum key is recoverable from the same phrase a wallet already backs up:

```typescript theme={null}
import { parseSeedPhrase } from "near-kit"

const pqKey = parseSeedPhrase("word1 word2 ... word12", {
  keyType: "ml-dsa-65",
  path: "m/44'/397'/0'", // default; bump the index for more keys
})
console.log(pqKey.publicKey.toString()) // ml-dsa-65:...
```

Derivation follows the SLIP-0010 extension proposed in [satoshilabs/slips#1968](https://github.com/satoshilabs/slips/pull/1968): the master node is `HMAC-SHA512(key = "ML-DSA-65 seed", data = BIP-39 seed)`, children use the standard SLIP-0010 hardened-only step, and the derived 32-byte node secret is the FIPS 204 seed ξ fed to ML-DSA key generation. Because the master salt differs from ed25519's, the ML-DSA-65 key derived from a phrase is unrelated to the ed25519 key derived from that same phrase.

<Note title="On-chain key handles">
  On-chain, an ML-DSA-65 access key is stored as a 32-byte hash, so `view_access_key_list` returns it as `ml-dsa-65-hash:...`, **not** the full key. Parse that form with `parseMlDsa65Handle()` for display and comparison — it is a read-only handle and cannot be used to sign or as an `addKey` public key (the full key is not recoverable from it).
</Note>
