Secure, one-time secret sharing API for developers.
Instead of pasting API keys in Slack, share them through SecretDrop: text is encrypted with AES-256-GCM, a one-time link is sent to the recipient via email. Once the link is opened or expires, the record is permanently deleted from the database - no trace left.
go 1.26+golangci-lint v2pre-commit
- Resend API Key
- Google OAuth app
- GitHub OAuth app
- Apple Developer account
- Stripe account
- Sentry account
Quick development setup for macOS and brew users:
brew install go golangci-lint pre-commitEnvironment variables for local development (backend):
# optional variables
export PORT="<port-number>" # default is: 8080
export SENTRY_DSN="<secret>" # sends to sentry if this variable is set!
export API_BASE_URL="..." # default is: http://localhost:8080
export FRONTEND_BASE_URL="..." # default is: http://localhost:3000
export APPLE_CLIENT_ID="<...>"
export APPLE_TEAM_ID="<...>"
export APPLE_KEY_ID="<...>"
export APPLE_PRIVATE_KEY="<...>"
export DATABASE_URL="..." # default is: file:db/secretdrop.db?_journal_mode=WAL
export STRIPE_WEBHOOK_FORWARD_TO="..." # default is: localhost:8080/billing/webhook
export SECRET_EXPIRY="..." # default is: 10m (10 minutes)
export CLEANUP_INTERVAL="..." # default is: 1m (1 minute)
# in development mode, fake mail send, slack hook goes to console only!
# just set some random value, real value required in "production" environment
export RESEND_API_KEY="<your-api-key>"
export SLACK_WEBHOOK_SUBSCRIPTIONS="<slack-webhook>"
export SLACK_WEBHOOK_NOTIFICATIONS="<slack-webhook>"
# required
export GOLANG_ENV="development" # default is: production
export JWT_SECRET="<secret>"
export GOOGLE_CLIENT_ID="<secret>"
export GOOGLE_CLIENT_SECRET="<secret>"
export GITHUB_CLIENT_ID="<secret>"
export GITHUB_CLIENT_SECRET="<secret>"
export ADMIN_USERNAME="<username>"
export ADMIN_PASSWORD="<secret>"
export STRIPE_PRICE_ID="<...>"
export STRIPE_SECRET_KEY="<secret>"
export STRIPE_WEBHOOK_SECRET="<secret>"
export FROM_EMAIL="Name <email>"
export REPLY_TO_EMAIL="<email>"
# Set Strip Product (your subscription Product) METADATA as -> project: secretdrop
export STRIPE_PROJECT_METAKEY="project"
export STRIPE_PROJECT_METADATA="secretdrop"Build time environment variables for frontend:
# remove these variables if you like to enable, "false" hides sign-in button.
export VITE_ENABLE_GOOGLE_SIGNIN="false"
export VITE_ENABLE_APPLE_SIGNIN="false"Run backend and frontend together:
git clone git@github.com:bilustek/secretdrop.git
cd secretdrop/
pre-commit install
stripe login # for webhooks
cd frontend/
npm install
cd ../
rakeRun the local server, hit: http://localhost:8080/docs, (Scalar UI) protected by
Basic Auth when ADMIN_USERNAME and ADMIN_PASSWORD are set!
Auth types:
- Bearer: JWT access token via
Authorization: Bearer <token>header (obtained through OAuth) - Basic: HTTP Basic Auth via
Authorization: Basic <base64>header (admin credentials from env vars) - Basic: Protected only when
ADMIN_USERNAMEandADMIN_PASSWORDare set; public otherwise
- User visits
/auth/google,/auth/github, or/auth/appleto start OAuth - After consent, the callback returns a JWT token pair (access + refresh)
- Use the access token in subsequent API requests:
Apple Sign-In notes: Apple uses
response_mode=form_post- the callback receives a POST withapplication/x-www-form-urlencoded(not a GET redirect like Google/GitHub). The server generates a short-lived ES256 client_secret JWT per request and verifies the returned id_token via Apple's JWKS endpoint (RS256).
- Encryption: AES-256-GCM with HKDF-SHA256 key derivation bound to the recipient's email
- Key never stored in DB - only carried in the URL fragment (
#portion) - URL fragments are not sent to the server or logged (RFC 3986)
- Email hashing: SHA-256 - raw email is never persisted
- One-time use: record is permanently deleted from DB after reveal
- Auto-cleanup: expired records are periodically purged
- Authentication: JWT Bearer tokens (15-min access, 30-day refresh)
- OAuth: Google + GitHub + Apple sign-in with CSRF state cookies
- Uğur Özyılmazel - Creator, maintainer
All PR’s are welcome!
fork(https://github.com/bilustek/secretdrop/fork)- Create your
branch(git checkout -b my-feature) commityours (git commit -am 'add some functionality')pushyourbranch(git push origin my-feature)- Then create a new Pull Request!
This project is licensed under MIT (MIT)
This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.