Generate one Profile. Share it. Transform data into a profile-specific envelope.
FISE is a keyless data-representation protocol for web applications: it replaces
directly readable JSON, text, and binary payloads with a profile-specific
reversible envelope. Instead of a secret encryption key, FISE uses generated
Profile runtime code as the reversible rule shared by the frontend and backend.
The encrypt and decrypt methods are operational names for that reversible
transform, not a cryptographic guarantee.
FISE is not encryption. It is a data-representation (obfuscation) layer.
encrypt/decryptname a reversible transform—not confidentiality, integrity, or authentication—and the generated Profile is public application code, not a secret key. Keep TLS, server-side authorization, and (for real secrets) authenticated encryption. See the security boundary.
Run fise generate once, commit and share the exact generated Profile, encrypt
on one side, and decrypt on the other. Each Profile contains a different verified
byte-transformation pipeline while remaining deterministic and reversible. The
same Profile handles structured data, text, and binary data such as images,
files, or videos; full binary transformation is the default.
With default full coverage, a captured FISE payload cannot be consumed directly as the original JSON, text, or file bytes. A basic scraper or generic decoder must integrate that deployment's matching Profile, positional context contract, and decrypt path. Different generated Profiles reduce reuse of one static signature or universal decoder across applications.
FISE returns a JSON-safe string for text and structured data, and binary output for binary input. Repetitive structured data is compressed automatically when that makes its internal payload smaller. Large binary data can be restored by range, one chunk at a time, or processed through WASM and workers. An optional edge mode transforms only the beginning and end of a binary value when lower transform cost matters more than covering its middle bytes. Envelopes can also carry a runtime TTL.
Keyless means there is no secret encryption-key lifecycle; it does not mean the Profile is secret. Generated Profile code, context conventions, and decrypt logic are visible to the frontend. A scraper that controls or instruments that runtime can still call or hook decrypt and read the restored data. Keep TLS, authentication, server-side authorization, cryptographic encryption, integrity protection, and input validation.
Read the engineering whitepaper for the design, boundaries, and evaluation method.
npm install fisenpx uses the project-local CLI, so no global installation is needed. FISE is
ESM-only and requires Node.js 20+ or a modern browser.
For a Python backend, also install the dependency-free Python 3.10+ runtime:
python -m pip install fisenpx fise generate ./src/fise.profile.tsA Profile is generated source code that tells FISE how to transform and restore data. Every generation samples a fresh independently randomized candidate and verifies it before writing. Commit the generated file to Git; do not edit it by hand.
If the backend is Python, choose it in the same generation command:
npx fise generate ./src/fise.profile.ts --backend pythonThis emits fise.profile.ts for the frontend and fise_profile.py for the
backend from one candidate. The two files carry the same fingerprint and are
verified for exact cross-language wire compatibility before either is written.
See the CLI reference for verify, --override, CI use, and
the complete command contract.
Frontend and backend must use the exact generated Profile artifact or JavaScript/Python pair from one command. Do not generate either side independently.
┌─────────────┐ ┌────────────────┐ ┌─────────────┐
│ Backend │──────▶│ One Profile │◀──────│ Frontend │
└──────┬──────┘ └────────────────┘ └──────▲──────┘
└────────────── FISE data ─────────────────────┘
In a JavaScript monorepo, keep the Profile in a shared package. For a Python
backend, keep the generated .ts/.py pair under one owner and distribute each
language artifact without regenerating it. Run fise verify on every copy and
confirm the fingerprint matches.
Context is an optional ordered list of values already known by both sides, for example a session ID and user ID:
const context = [sessionId, userId, "orders", "v1"];Context makes the result depend on those values. Decrypt with the same values
in the same order. FISE does not store them in the envelope, but they are not a
secret key or an authorization check. sessionId here must be a client-visible,
non-credential identifier—not an authentication token or protected cookie. If
context is not useful for your flow, omit the second argument on both sides.
import { Fise } from "fise";
import profile from "./fise.profile.js";
const fise = new Fise(profile);
const context = [sessionId, userId, "orders", "v1"];
const encryptedData = fise.encrypt(order, context);The Python backend API is the same small profile-bound model:
from fise import Fise
from fise_profile import profile
fise = Fise(profile)
context = [session_id, user_id, "orders", "v1"]
encrypted_data = fise.encrypt(order, context)For text or structured data, encryptedData is a JSON-safe Base64URL string
that can be placed directly in the application's existing API response.
import { Fise } from "fise";
import profile from "./fise.profile.js";
const fise = new Fise(profile);
const context = [sessionId, userId, "orders", "v1"];
const order = fise.decrypt(encryptedData, context);The restored value has the original text, structured, or binary type. The same Profile can also be used in the opposite direction. Validate restored structured data with the application's normal response schema before using it.
See the runnable HTTP web-application example, the Python agent-backend interoperability example, the web integration guide, and the examples guide.
Binary input returns binary FISE data:
const encryptedFile = fise.encrypt(fileBytes, context);
const restoredFile = fise.decrypt(encryptedFile, context);Restore only a requested byte range without restoring the whole file:
const range = fise.decryptRange(
encryptedFile,
{ start: 1_000, endExclusive: 2_000 },
context
);Or restore chunks as the application asks for them:
for await (const chunk of fise.decryptProgressive(encryptedFile, context, {
chunkSize: 256 * 1024
})) {
consume(chunk);
}Full transformation is the default. For large videos or files, edge mode can reduce transform work by processing only the first and last resolved bytes:
const mediaFise = new Fise(profile, {
binary: { mode: "edges" }
});
const encryptedVideo = mediaFise.encrypt(videoBytes, context);Edge mode uses 1 MiB per side by default. Advanced users can set edgeBytes in
the same constructor option. decrypt, range, and progressive restoration read
the resolved policy from the envelope; consumers do not repeat it. The middle
bytes remain untransformed and can be inspected, so edge mode is an explicit
performance trade-off—not the same coverage as the default full mode. It still
returns one complete in-memory envelope.
See binary data for coverage choices and large-file limits.
Set the lifetime once on the encrypting instance:
const fise = new Fise(profile, { ttlSeconds: 30 });
const encryptedData = fise.encrypt(data, context);Python uses Fise(profile, ttl_seconds=30) for the same wire behavior.
The consumer calls decrypt normally. At the expiry second, FISE throws
ENVELOPE_EXPIRED. This is a normal-runtime freshness rule, not cryptographic
expiration or replay prevention; a controlled client can patch the check or
its clock. Browser-facing flows must also allow for network delay and clock
skew between producer and consumer; avoid very short TTLs when correctness
depends on separate device clocks.
FISE throws on failure by default. An application that prioritizes availability
can explicitly return the original input when ordinary encrypt or decrypt
fails:
const fise = new Fise(profile, { strict: false });
const encryptedOrRaw = fise.encrypt(data, context);
const restoredOrRaw = fise.decrypt(received, context);Python uses Fise(profile, strict=False) for the equivalent opt-in behavior.
Expiration and clock failures always throw. Range and progressive methods also remain strict. A failed encryption can expose the original data, so the application must support and monitor both outcomes. See the security boundary before enabling fallback.
- Get started: Quick start, web application integration, runnable examples, and CLI reference.
- Understand FISE: Profiles and context, binary data, and WASM and workers.
- Reference: FISE 2.0 specification, security boundary, engineering whitepaper, and roadmap.
- Contribute or automate: contributing guide and agent integration guide.
FISE is available under the MIT License.