Skip to main content
This guide takes you from nothing to a working encrypt/decrypt round trip, then shows the pattern nearly every real integration uses it for: keeping API keys and credentials out of your code while still using them inside a Lit Action. Administrative pages are linked where you meet them. The model in two sentences: Lit.Actions.Encrypt seals data with an AES key derived — inside the TEE — from a PKP you own, and that key never exists outside the enclave. So “who can decrypt this?” reduces to “which action code is permitted to use that PKP?”, which is on-chain configuration you control. If PKPs, groups, or usage keys are new to you, keep Core Concepts open in a second tab. Coming from Lit V1 / Naga access-control conditions? Read the model comparison first — this is a different (and simpler) approach.

What you’ll build

  1. A vault PKP — the key your ciphertexts are sealed under.
  2. An action that encrypts a secret and returns the ciphertext.
  3. An action that decrypts it — and only runs because you’ve authorized it.
1

Create an account and add funds

If you haven’t yet, follow the Quick Start through funding: create an account (store the account API key — it’s shown once) and add at least $5.00 of credits. Metered calls without credits fail with 402 Payment Required.
Admin reference: API Keys · Pricing · Errors.
2

Mint a vault PKP

The returned wallet_address is your pkpId. Treat one PKP as one trust boundary: everything encrypted under it is decryptable by any action allowed to use it. Separate app secrets from user data by minting separate PKPs — see PKP wallets as data vaults.
3

Encrypt a secret

The plaintext transits this one request (over TLS, into the TEE). For most secrets that’s fine — encrypt once from a trusted machine. Never log it, and never leave it in shell history you don’t control.
4

Store the ciphertext — anywhere

The ciphertext is safe to store in public: a database, IPFS, a smart contract, an environment variable, even hardcoded in client code. Its confidentiality comes from the PKP-derived key in the TEE, not from where it sits. Storage trade-offs are covered in Secrets → where to put the ciphertext.
5

Decrypt it back

Round trip complete. In production you’ll rarely return the plaintext like this — you’ll use it inside the action (call an API with it, sign with it) and return only the result. Returning or logging decrypted secrets is the #1 leak path; see common mistakes.
6

Production posture: lock down who can decrypt

Right now your account key can run any code against the vault PKP. Locking it down is on-chain configuration:
  1. Pin the decrypt action. Publish your decrypting action to IPFS, register the CID in a group, and add the vault PKP to the same group. Now only that exact code can ever produce the plaintext.
  2. Scope a usage key to execute_in_groups: [thatGroup] for whatever service calls it — it can trigger the decrypt flow but can’t run arbitrary code against your vault.
  3. Gate inside the action if you need caller-level rules: token balance, NFT ownership, a caller signature. The gate is plain JavaScript — see gating logic.
The enforcement split — what the chain guarantees vs. what your action code guarantees — is summarized in Secrets → what’s enforced where.
Admin reference: API Keys · Groups · Dashboard.

The pattern you’ll actually use: encrypted secrets inside actions

Most encryption use on Lit isn’t “encrypt user files” — it’s giving your action a secret without giving it to anyone else. Encrypt an API key once, pass the ciphertext as a js_params value (or hardcode it in the action), and decrypt at runtime inside the TEE:
The same shape secures paid RPC URLs, database connection strings, LLM API keys, and webhook signing secrets. Full treatment: Secrets and securing RPC URLs.

Where encryption goes from here

Secrets lifecycle

The full vault model: minting, permitting, storing, bundling multiple secrets, and rotation.

Token-gated decryption

Decrypt only for callers who hold a token or NFT, or who sign a challenge — gates written as plain JS.

Coming from Lit V1?

How PKP-derived encryption differs from BLS access-control conditions, and when to use each.

SDK reference

Exact signatures for Lit.Actions.Encrypt and Lit.Actions.Decrypt.

Encrypted state at scale

A dark pool that stores every order as ciphertext in Postgres and matches batches inside the enclave.

Combine with signing

Decrypt a credential, act on it, sign the result — the two primitives compose in one action.

Administrative checklist for an encryption app

  • Separate vault PKPs per trust boundary (app secrets vs. user data) — Patterns
  • Decrypt action published to IPFS, CID pinned in a group with the vault PKP — Dashboard
  • Usage keys scoped to that group only; account key never ships — API Keys
  • No action returns or logs plaintext secrets — Common mistakes
  • Rotation plan: re-encrypt, replace ciphertext, invalidate the old secret upstream — Secrets
  • Credit balance monitored; decrypt calls are metered like any action — Pricing