Skip to main content

Overview

The File Key Service provides persistent, file-based storage for private keys in Node.js environments. Keys are stored in the local filesystem and automatically loaded when needed.
File Key Service is only available in Node.js environments. For browser applications, use IDB Key Service.

Creating a File Key Service

Method Signature

createFileKeyService(args?: CreateFileKeyServiceArgs): FileKeyService
safeCreateFileKeyService(args?: CreateFileKeyServiceArgs): Result<FileKeyService, Error>

Parameters

path
string
Directory path for storing key files. Defaults to .near-api-ts:key-vault in the current working directory.

Interface

The File Key Service implements the following interface:
interface FileKeyService {
  // Add a key pair to the service
  addKeyPair(keyPair: KeyPair): Promise<void>;
  safeAddKeyPair(keyPair: KeyPair): Promise<Result<void, Error>>;
  
  // Check if a key pair exists
  hasKeyPair(publicKey: PublicKey): Promise<boolean>;
  safeHasKeyPair(publicKey: PublicKey): Promise<Result<boolean, Error>>;
  
  // Remove a key pair from the service
  removeKeyPair(keyPair: KeyPair): Promise<void>;
  safeRemoveKeyPair(keyPair: KeyPair): Promise<Result<void, Error>>;
  
  // Clear all key pairs
  clear(): Promise<void>;
  safeClear(): Promise<Result<void, Error>>;
  
  // Sign a transaction
  signTransaction(args: SignTransactionArgs): Promise<SignedTransaction>;
  safeSignTransaction(args: SignTransactionArgs): Promise<Result<SignedTransaction, Error>>;
}

Examples

Create with Default Path

import { createFileKeyService } from 'near-api-ts/node';

// Keys stored in ./.near-api-ts:key-vault
const keyService = createFileKeyService();

console.log('File key service ready');

Create with Custom Path

import { createFileKeyService } from 'near-api-ts/node';
import path from 'node:path';

// Store keys in a custom directory
const keyService = createFileKeyService({
  path: path.join(process.env.HOME, '.near-credentials')
});

Add Key Pair

import { createFileKeyService, randomEd25519KeyPair } from 'near-api-ts';

const keyService = createFileKeyService();
const keyPair = randomEd25519KeyPair();

// Add key pair (persists to disk)
await keyService.addKeyPair(keyPair);

console.log('Key pair added:', keyPair.publicKey);

Check if Key Exists

const exists = await keyService.hasKeyPair(keyPair.publicKey);

if (exists) {
  console.log('Key pair exists in storage');
} else {
  console.log('Key pair not found');
}

Remove Key Pair

import { createFileKeyService, randomEd25519KeyPair } from 'near-api-ts';

const keyService = createFileKeyService();
const keyPair = randomEd25519KeyPair();

// Add and then remove
await keyService.addKeyPair(keyPair);
await keyService.removeKeyPair(keyPair);

console.log('Key pair removed');

Clear All Keys

// Remove all stored key pairs
await keyService.clear();

console.log('All key pairs cleared');

Sign Transaction

import { 
  createFileKeyService, 
  randomEd25519KeyPair, 
  transfer 
} from 'near-api-ts';

const keyService = createFileKeyService();
const keyPair = randomEd25519KeyPair();

// Add key to service
await keyService.addKeyPair(keyPair);

// Get recent block hash
const block = await client.getBlock();

// Sign transaction
const signedTx = await keyService.signTransaction({
  transaction: {
    signerAccountId: 'sender.near',
    signerPublicKey: keyPair.publicKey,
    receiverAccountId: 'receiver.near',
    nonce: 1,
    blockHash: block.rawRpcResult.header.hash,
    action: transfer({ amount: { near: '1' } })
  }
});

console.log('Transaction signed');

Safe Operations with Error Handling

import { createFileKeyService, randomEd25519KeyPair } from 'near-api-ts';

const keyPair = randomEd25519KeyPair();
const keyService = createFileKeyService();

// Safe add
const addResult = await keyService.safeAddKeyPair(keyPair);
if (!addResult.ok) {
  console.error('Failed to add key:', addResult.error);
  return;
}

// Safe sign
const signResult = await keyService.safeSignTransaction({
  transaction: {
    signerAccountId: 'sender.near',
    signerPublicKey: keyPair.publicKey,
    receiverAccountId: 'receiver.near',
    nonce: 1,
    blockHash: recentBlockHash,
    action: transfer({ amount: { near: '1' } })
  }
});

if (signResult.ok) {
  console.log('Transaction signed:', signResult.value);
} else {
  console.error('Failed to sign:', signResult.error);
}

// Clean up
await keyService.removeKeyPair(keyPair);

Use with Client

import { createClient, createFileKeyService } from 'near-api-ts';

const keyService = createFileKeyService();

const client = createClient({
  network: 'testnet',
  keyService
});

// Client can now sign transactions automatically using stored keys
const result = await client.sendTransaction({
  signerAccountId: 'sender.testnet',
  signerPublicKey: storedPublicKey,
  receiverAccountId: 'receiver.testnet',
  actions: [/* ... */]
});

Import Existing Keys

import { createFileKeyService, keyPair } from 'near-api-ts';
import fs from 'node:fs/promises';

const keyService = createFileKeyService();

// Import key from file or environment
const privateKeyString = process.env.NEAR_PRIVATE_KEY;
const keypairObj = keyPair({ privateKey: privateKeyString });

await keyService.addKeyPair(keypairObj);
console.log('Imported key:', keypairObj.publicKey);

File Storage Structure

Keys are stored in the filesystem with the following structure:
.near-api-ts:key-vault/
├── ed25519:ABC123.../
│   └── private.key
├── ed25519:DEF456.../
│   └── private.key
└── secp256k1:GHI789.../
    └── private.key
Each key pair is stored in a directory named after its public key, with the private key stored in a private.key file.

Error Types

Creation Errors

  • CreateFileKeyService.Internal - Internal error during creation

Sign Transaction Errors

  • FileKeyService.SignTransaction.Args.InvalidSchema - Invalid transaction arguments
  • FileKeyService.SignTransaction.Internal - Internal signing error

Security Considerations

File System Security
  • Key files are stored in plain text on disk
  • Ensure proper file system permissions (chmod 600)
  • Never commit key directories to version control
  • Add key directory to .gitignore

Secure File Permissions

import { createFileKeyService } from 'near-api-ts/node';
import fs from 'node:fs/promises';
import path from 'node:path';

const keyDir = path.join(process.env.HOME, '.near-credentials');
const keyService = createFileKeyService({ path: keyDir });

// Set secure permissions (Unix/Linux/Mac)
try {
  await fs.chmod(keyDir, 0o700); // rwx------
  console.log('Secure permissions set');
} catch (error) {
  console.error('Failed to set permissions:', error);
}

.gitignore

# Ignore NEAR key storage
.near-api-ts:key-vault/
.near-credentials/
*.near-keys/

Use Cases

Server Applications

Backend services that need persistent key storage

CLI Tools

Command-line applications managing NEAR accounts

Development

Local development with persistent test accounts

Automated Tasks

Scripts and cron jobs that sign transactions

Best Practices

Store keys in a secure location with restricted permissions:
// Good: User's home directory with restricted access
const keyService = createFileKeyService({
  path: path.join(os.homedir(), '.near-credentials')
});

// Bad: Project directory (might be committed to git)
const keyService = createFileKeyService({
  path: './keys'
});
Use different key storage paths for different environments:
const keyPath = process.env.NODE_ENV === 'production'
  ? '/var/secrets/near-keys'
  : path.join(os.homedir(), '.near-credentials-dev');

const keyService = createFileKeyService({ path: keyPath });
Implement key rotation for long-running applications:
async function rotateKey(keyService: FileKeyService, oldKeyPair: KeyPair) {
  // Generate new key
  const newKeyPair = randomEd25519KeyPair();
  
  // Add new key
  await keyService.addKeyPair(newKeyPair);
  
  // Update on-chain (add new access key, remove old)
  // ...
  
  // Remove old key from storage
  await keyService.removeKeyPair(oldKeyPair);
  
  return newKeyPair;
}
Implement a backup strategy for important keys:
import { createFileKeyService } from 'near-api-ts/node';
import fs from 'node:fs/promises';

async function backupKeys(keyService: FileKeyService, backupPath: string) {
  const keyDir = '.near-api-ts:key-vault';
  await fs.cp(keyDir, backupPath, { recursive: true });
  console.log(`Keys backed up to ${backupPath}`);
}

Migration from near-api-js

If you’re migrating from near-api-js, the File Key Service is similar to UnencryptedFileSystemKeyStore:
// near-api-js (old)
import { keyStores } from 'near-api-js';
const keyStore = new keyStores.UnencryptedFileSystemKeyStore(keyPath);

// near-api-ts (new)
import { createFileKeyService } from 'near-api-ts/node';
const keyService = createFileKeyService({ path: keyPath });

Source Code

  • Implementation: node/src/fileKeyService/fileKeyService.ts:28
  • Type definitions: node/types/fileKeyService/fileKeyService.ts:1
  • Tests: node/tests/unit/fileKeyService/signTransaction.test.ts:1