Documenso, with a key nobody holds. What a signed document gives away, its title, the recipients, the email sent to signers and the signatures themselves is sealed before it ever reaches the database, encrypted with a key that is never assembled anywhere, not even to decrypt. The key lives as threshold shares across the Tide network, so the classic breach, someone walking off with your database or a backup, turns up nothing readable.
- Your database holds only ciphertext. A stolen dump or a leaked backup is useless to whoever takes it.
- There is no standing key to steal. The vendor key is never whole, not in this app and not on any single server.
- Reads are governed, not assumed. A quorum grants the reading role. Revoke it and reads stop everywhere, at once.
- Nobody juggles keys. People keep the login they already have. The gate is a role, not a keyfile they can lose.
- Nothing else changes. Documenso works exactly as it does upstream, and sealing stays off until you turn it on.
Sealing is off until you point Documenso at a minidauth sidecar; unconfigured, it behaves exactly like upstream.
-
Bring up the backend. In a checkout of minidauth:
cp operators.example.json operators.json docker compose -f docker-compose.yml -f docker-compose.seal.yml up -d # create a vendor key once (a licensed step; see that repo's docs/running.md) ./bootstrap.shThis runs the sealing sidecar on
http://localhost:3021and writes a signing key to./keys/usertoken.key. Full detail: minidauth's docs/sealing.md. -
Point Documenso at it. Set these in its environment, then start Documenso as usual:
MINIDAUTH_SEAL_URL=http://localhost:3021 MINIDAUTH_SEAL_SIGNING_KEY_FILE=/absolute/path/to/minidauth/keys/usertoken.key # optional, to also threshold-sign completed documents: MINIDAUTH_SIGN_URL=http://localhost:3021Now document titles, recipient names, the subject and body of signer emails, and the signatures themselves are sealed before they reach the database.
-
Grant a reader. Sealed fields open only for a user the quorum granted the
crm-readerrole. Grant it to a Documenso user by their id, from the minidauth checkout:DEMO_UID=<documenso user id> ./bootstrap.sh
Revoke it in minidauth and their reads go dark, with no change to Documenso.
The Open Source DocuSign Alternative.
Learn more »
Discord
·
Website
·
Documentation
·
Issues
·
Upcoming Releases
·
Roadmap
Signing documents digitally should be fast and easy and should be the best practice for every document signed worldwide. This is technically quite easy today, but it also introduces a new party to every signature: The signing tool providers. While this is not a problem in itself, it should make us think about how we want these providers of trust to work. Documenso aims to be the world's most trusted document-signing tool. This trust is built by empowering you to self-host Documenso and review how it works under the hood.
Join us in creating the next generation of open trust infrastructure.
This fork adds two things on top of Documenso, both built on minidauth and the Tide
ORK cohort, and both off unless configured (MINIDAUTH_SEAL_URL unset means the app behaves exactly
like upstream):
-
Sealed at rest. A document's title, a recipient's name, the email subject and message sent to signers, the typed or drawn signatures, and the text a signer enters are sealed before they reach Postgres. The database, and the app process, only ever hold
ms1:ciphertext. The vendor key lives as threshold shares across the ORK network and is never assembled here, so a stolen database or a leaked backup reveals nothing. Records are opened again in-request, and only for a user a quorum granted the reading role; a recipient opening a signing link opens the document on the owner's authority once their token is verified. Revoke the role and reads stop everywhere. A Prisma client extension does the sealing (packages/prisma/extensions/); the recipient's email stays in the clear because it is the routing/signing-link key the database matches on. -
Signed by a quorum. When a recipient completes signing, the Tide ORK cohort threshold-signs a canonical statement about the completion (envelope, signer, item hash, time), gated on the signer's quorum-granted role. The 64-byte vendor-key signature and the statement are stored on the recipient row (
cohortSignature/cohortStatement) and are verifiable by anyone with the vendor public key — no signing key is ever assembled, in Documenso or the sidecar, so no operator and no stolen database can forge or alter a completed signature. Seepackages/prisma/extensions/minidauth-sign.ts. Best-effort and guarded: a signing service being down never blocks a person from signing.
Setup uses a sealing minidauth and (optionally) a separate signing key; see the seal extension and the
MINIDAUTH_SEAL_URL / MINIDAUTH_SEAL_SIGNING_KEY_FILE / MINIDAUTH_SIGN_URL variables.
- Try Documenso by self-hosting it or signing up at documenso.com.
- Tell us what you think in the Discussions.
- Join the Discord server for any questions and getting to know other community members.
- ⭐ the repository to help us raise awareness.
- Open detailed issues to report bugs or propose features.
Note: We no longer accept external pull requests, aside from a small group of trusted contributors we reach out to directly. The best way to contribute is through detailed issues. Read Why We're Pausing External Pull Requests for the reasoning.
- Documenso stays open source. You can read, audit, run, and fork the code.
- To report issues or propose changes, see our contribution guide.
Contact us if you are interested in our Enterprise plan for large organizations that need extra flexibility and control.
- TypeScript - Language
- React Router v7 - Framework
- Hono - Server
- Prisma - ORM
- Tailwind CSS - CSS
- shadcn/ui + Radix UI - Component Library
- react-email - Email Templates
- Lingui - Internationalization
- tRPC - API
- @libpdf/core - PDF Signatures
- pdf.js - Viewing PDFs
- @cantoo/pdf-lib - PDF manipulation
- Stripe - Payments
- Biome - Linting & Formatting
- Playwright - E2E Testing
To run Documenso locally, you will need
- Node.js (v24 or above)
- Postgres SQL Database
- Docker (optional)
Note: This is a quickstart for developers. It assumes that you have both docker and docker-compose installed on your machine.
Want to get up and running quickly? Follow these steps:
- Fork this repository to your GitHub account.
After forking the repository, clone it to your local device by using the following command:
git clone https://github.com/<your-username>/documenso-
Set up your
.envfile using the recommendations in the.env.examplefile. Alternatively, just runcp .env.example .envto get started with our handpicked defaults. -
Run
npm run dxin the root directory- This will spin up a postgres database and inbucket mailserver in a docker container.
-
Run
npm run devin the root directory -
Want it even faster? Just use
npm run d-
App - http://localhost:3000
-
Incoming Mail Access - http://localhost:9000
-
Database Connection Details
- Port: 54320
- Connection: Use your favorite database client to connect using the provided port.
-
S3 Storage Dashboard - http://localhost:9001
Follow the manual setup guide to configure Documenso on your local machine.
- Click below to launch a ready-to-use Gitpod workspace in your browser.
We support DevContainers for VSCode. Click here to get started.
If you're a visual learner and prefer to watch a video walkthrough of setting up Documenso locally, check out this video:
We provide official Docker images on DockerHub and GitHub Container Registry.
For setup instructions, see the Docker Deployment and Docker Compose guides.
We support a variety of deployment methods including Docker, Docker Compose, Railway, Kubernetes, and manual deployment.
For full instructions, requirements, and configuration details, see the Self Hosting documentation.
Note
Want to see another provider listed here? Please open a provider request instead of a PR so the community can signal interest. PRs adding deploy badges without a prior issue will be closed.
|
|
|
|
|
|
If you believe you have found a security vulnerability in Documenso, please report it through our Security Policy. We prioritize private reports via GitHub Security Advisories. See SECURITY.md for scope and details.
For troubleshooting self-hosted deployments, see the Troubleshooting guide and Tips & Common Pitfalls.
When using the developer quickstart, an Inbucket server will be spun up in a docker container that will store all outgoing emails locally for you to view.
The Web UI can be found at http://localhost:9000, while the SMTP port will be on localhost:2500.
Wrap your package script with the with:env script like such:
npm run with:env -- npm run myscript
The same can be done when using npx for one of the bin scripts:
npm run with:env -- npx myscript
This will load environment variables from your .env and .env.local files.

