Skip to main content

Overview

Access keys grant permissions to sign transactions on behalf of an account. NEAR supports two types:
  • Full Access Keys - Can perform any action on the account
  • Function Call Keys - Limited to calling specific contract methods

Full Access Keys

addFullAccessKey()

Adds a key with full permissions to an account.
import { addFullAccessKey } from '@near-api-ts/universal';

const action = addFullAccessKey({
  publicKey: 'ed25519:...',
});

Parameters

publicKey
string
required
The public key to add. Format: ed25519: or secp256k1: followed by the base58-encoded key.

Returns

{
  actionType: 'AddKey',
  accessType: 'FullAccess',
  publicKey: string
}

Example

import { addFullAccessKey, randomEd25519KeyPair } from '@near-api-ts/universal';

const newKeyPair = randomEd25519KeyPair();

await signer.executeTransaction({
  intent: {
    receiverAccountId: 'alice.near',
    action: addFullAccessKey({ publicKey: newKeyPair.publicKey })
  }
});

console.log('Full access key added:', newKeyPair.publicKey);
console.log('Private key:', newKeyPair.secretKey);

Function Call Keys

addFunctionCallKey()

Adds a key with limited permissions to call specific contract methods.
import { addFunctionCallKey } from '@near-api-ts/universal';

const action = addFunctionCallKey({
  publicKey: 'ed25519:...',
  contractAccountId: 'contract.near',
  allowedFunctions: ['method1', 'method2'],
  gasBudget: { near: '0.25' }
});

Parameters

publicKey
string
required
The public key to add
contractAccountId
string
required
The contract account that this key can call
allowedFunctions
string[]
List of method names this key can call. If omitted, can call any method on the contract.
gasBudget
NearTokenArgs
Maximum allowance for gas fees. If omitted, no limit is set.

Returns

{
  actionType: 'AddKey',
  accessType: 'FunctionCall',
  publicKey: string,
  contractAccountId: string,
  allowedFunctions?: string[],
  gasBudget?: NearTokenArgs
}

Example

import { addFunctionCallKey, near, randomEd25519KeyPair } from '@near-api-ts/universal';

const limitedKeyPair = randomEd25519KeyPair();

await signer.executeTransaction({
  intent: {
    receiverAccountId: 'alice.near',
    action: addFunctionCallKey({
      publicKey: limitedKeyPair.publicKey,
      contractAccountId: 'game.near',
      allowedFunctions: ['play_move', 'claim_reward'],
      gasBudget: near('0.25')
    })
  }
});

Complete Examples

Add Multiple Keys

import { 
  addFullAccessKey,
  addFunctionCallKey,
  near,
  randomEd25519KeyPair
} from '@near-api-ts/universal';

const backupKey = randomEd25519KeyPair();
const appKey = randomEd25519KeyPair();

await signer.executeTransaction({
  intent: {
    receiverAccountId: 'alice.near',
    actions: [
      addFullAccessKey({ publicKey: backupKey.publicKey }),
      addFunctionCallKey({
        publicKey: appKey.publicKey,
        contractAccountId: 'app.near',
        allowedFunctions: ['vote', 'submit'],
        gasBudget: near('0.25')
      })
    ]
  }
});

console.log('Backup key:', backupKey.secretKey);
console.log('App key:', appKey.secretKey);

Create Account with Keys

import { 
  createAccount,
  transfer,
  addFullAccessKey,
  addFunctionCallKey,
  near,
  randomEd25519KeyPair
} from '@near-api-ts/universal';

const ownerKey = randomEd25519KeyPair();
const appKey = randomEd25519KeyPair();

await signer.executeTransaction({
  intent: {
    receiverAccountId: 'new.alice.near',
    actions: [
      createAccount(),
      transfer({ amount: near('10') }),
      addFullAccessKey({ publicKey: ownerKey.publicKey }),
      addFunctionCallKey({
        publicKey: appKey.publicKey,
        contractAccountId: 'app.near',
        gasBudget: near('0.5')
      })
    ]
  }
});

Key Rotation

import { 
  addFullAccessKey,
  deleteKey,
  randomEd25519KeyPair
} from '@near-api-ts/universal';

const newKeyPair = randomEd25519KeyPair();
const oldPublicKey = 'ed25519:OldKeyHere...';

// Add new key and remove old key atomically
await signer.executeTransaction({
  intent: {
    receiverAccountId: 'alice.near',
    actions: [
      addFullAccessKey({ publicKey: newKeyPair.publicKey }),
      deleteKey({ publicKey: oldPublicKey })
    ]
  }
});

console.log('Key rotated successfully');
console.log('New private key:', newKeyPair.secretKey);
Be careful with key rotation. If you delete all access keys, you’ll lose access to the account permanently.

App-Specific Keys

import { addFunctionCallKey, near, randomEd25519KeyPair } from '@near-api-ts/universal';

// Key for DEX trading
const dexKey = randomEd25519KeyPair();
await signer.executeTransaction({
  intent: {
    receiverAccountId: 'alice.near',
    action: addFunctionCallKey({
      publicKey: dexKey.publicKey,
      contractAccountId: 'dex.near',
      allowedFunctions: ['swap', 'add_liquidity', 'remove_liquidity'],
      gasBudget: near('1')
    })
  }
});

// Key for NFT marketplace
const nftKey = randomEd25519KeyPair();
await signer.executeTransaction({
  intent: {
    receiverAccountId: 'alice.near',
    action: addFunctionCallKey({
      publicKey: nftKey.publicKey,
      contractAccountId: 'marketplace.near',
      allowedFunctions: ['buy', 'make_offer'],
      gasBudget: near('0.5')
    })
  }
});

Unlimited Function Calls

import { addFunctionCallKey, randomEd25519KeyPair } from '@near-api-ts/universal';

const appKey = randomEd25519KeyPair();

// Can call any method on the contract
await signer.executeTransaction({
  intent: {
    receiverAccountId: 'alice.near',
    action: addFunctionCallKey({
      publicKey: appKey.publicKey,
      contractAccountId: 'app.near'
      // No allowedFunctions - can call any method
      // No gasBudget - no spending limit
    })
  }
});
Function call keys without restrictions can call any method but still cannot transfer tokens directly or delete the account.

Using Different Key Types

import { 
  addFullAccessKey,
  randomEd25519KeyPair,
  randomSecp256k1KeyPair
} from '@near-api-ts/universal';

// Ed25519 key (most common)
const ed25519Key = randomEd25519KeyPair();
await signer.executeTransaction({
  intent: {
    receiverAccountId: 'alice.near',
    action: addFullAccessKey({ publicKey: ed25519Key.publicKey })
  }
});

// Secp256k1 key (compatible with Ethereum)
const secp256k1Key = randomSecp256k1KeyPair();
await signer.executeTransaction({
  intent: {
    receiverAccountId: 'alice.near',
    action: addFullAccessKey({ publicKey: secp256k1Key.publicKey })
  }
});

Error Handling

import { 
  addFullAccessKey,
  randomEd25519KeyPair,
  isNatError
} from '@near-api-ts/universal';

try {
  const newKeyPair = randomEd25519KeyPair();
  
  await signer.executeTransaction({
    intent: {
      receiverAccountId: 'alice.near',
      action: addFullAccessKey({ publicKey: newKeyPair.publicKey })
    }
  });
} catch (error) {
  if (isNatError(error)) {
    if (error.kind === 'CreateAction.AddFullAccessKey.Args.InvalidSchema') {
      console.error('Invalid public key format');
    }
  }
}

Safe Variants

import { 
  safeAddFullAccessKey,
  safeAddFunctionCallKey,
  near
} from '@near-api-ts/universal';

// Safe full access key
const fullKeyResult = safeAddFullAccessKey({ 
  publicKey: 'ed25519:...' 
});

if (!fullKeyResult.ok) {
  console.error('Invalid full access key:', fullKeyResult.error.kind);
  return;
}

// Safe function call key
const funcKeyResult = safeAddFunctionCallKey({
  publicKey: 'ed25519:...',
  contractAccountId: 'contract.near',
  gasBudget: near('0.25')
});

if (!funcKeyResult.ok) {
  console.error('Invalid function call key:', funcKeyResult.error.kind);
  return;
}

Common Errors

  • CreateAction.AddFullAccessKey.Args.InvalidSchema - Invalid public key format
  • CreateAction.AddFullAccessKey.Internal - Internal error
  • CreateAction.AddFunctionCallKey.Args.InvalidSchema - Invalid parameters
  • CreateAction.AddFunctionCallKey.Internal - Internal error
  • Key already exists - Adding a key that’s already on the account

Best Practices

DO:
  • Use full access keys for account owners
  • Use function call keys for applications
  • Store private keys securely
  • Set gas budgets on function call keys
  • Limit allowed functions when possible
  • Keep backup keys in secure locations
  • Rotate keys periodically
DON’T:
  • Don’t share private keys
  • Don’t delete all keys from an account
  • Don’t use full access keys in untrusted applications
  • Don’t set unlimited gas budgets without good reason
  • Don’t lose your private keys - they can’t be recovered

Key Permission Comparison

ActionFull AccessFunction Call
Transfer tokens
Deploy contracts
Add/delete keys
Delete account
Call contracts✅ (limited)
Stake tokens

See Also