Features Pricing
Start My Free Trial

Security

How MakeEmWait protects your data and your users' data.

MakeEmWait implements defense-in-depth security across multiple layers — authentication, data protection, bot filtering, and network controls. This page covers the security measures that protect both your account and your users’ data.

Authentication

MakeEmWait supports two authentication methods: JWT tokens for browser-based sessions and API keys for programmatic access.

JWT Authentication

MakeEmWait uses a dedicated authentication service for user management. When you log in, the auth service returns an ID token (JWT) signed with RSA256. Every authenticated API request is verified server-side, validating the token’s signature, expiry, audience, and issuer.

Tokens can be passed in two ways:

Method Format
Authorization header Authorization: Bearer <token>
Query parameter ?token=<token>

Tokens expire after 1 hour. After expiry, you must re-authenticate to get a new token.

API Key Authentication

Every account gets a personal API key for programmatic access. API keys use the format mew_live_ followed by 24 random bytes, giving 192 bits of entropy.

Keys are SHA-256 hashed before storage. The raw key is never stored in the database – it is shown only once at creation or regeneration and cannot be retrieved later. If you lose your key, you must regenerate a new one.

When you authenticate with an API key, MakeEmWait hashes the key you provide and looks up the matching hash in the database. If a match is found, the request is authenticated as that user.

Regeneration requires JWT authentication. You cannot regenerate an API key using the API key itself. This is a deliberate security measure – if a key is compromised, an attacker cannot use it to issue a replacement key and lock you out.

Admin API Key

A separate admin API key is used for internal operations. This key is compared using timing-safe comparison (crypto.timingSafeEqual) to prevent timing attacks, where an attacker could measure response times to guess the key character by character.

Bot Protection

Public signup forms include a honeypot field – a hidden form field named website that is invisible to real users via CSS but visible to automated bots that fill in every field.

When a bot fills in the honeypot field, the API returns a fake 201 response with fabricated signup data (a fake position, a fake referral token). The bot believes the signup succeeded, but no record is actually created in the database.

This approach blocks automated form submissions without requiring CAPTCHAs or any user interaction.

reCAPTCHA v3 Bot Protection

In addition to the honeypot field, you can enable Google reCAPTCHA v3 for invisible bot scoring on your signup forms. reCAPTCHA v3 runs in the background without any user interaction and assigns each visitor a score from 0.0 (likely bot) to 1.0 (likely human).

Enabling reCAPTCHA

  1. Get a reCAPTCHA v3 site key from the Google reCAPTCHA admin console. Choose “reCAPTCHA v3” and add your domain(s).

  2. Get your secret key from the same reCAPTCHA admin console (different from the site key — the secret key stays on the server).

  3. Enable it on your waitlist:

PATCH /waitlists/{waitlist_id}
{
  "settings": {
    "captcha_enabled": true,
    "captcha_site_key": "your-recaptcha-v3-site-key",
    "captcha_secret_key": "your-recaptcha-v3-secret-key",
    "captcha_threshold": 0.5
  }
}
Setting Type Description
captcha_enabled boolean Enable or disable reCAPTCHA v3
captcha_site_key string (max 100 chars) Your reCAPTCHA v3 site key (public, embedded in the form)
captcha_secret_key string (max 100 chars) Your reCAPTCHA v3 secret key (private, used server-side to verify tokens)
captcha_threshold number (0-1) Minimum score required to pass (default: 0.5). Scores below this are rejected. Higher values are stricter.

How It Works

When reCAPTCHA is enabled:

  • The hosted signup page and embed widget automatically load the reCAPTCHA v3 script using your site key
  • When a user submits the form, a reCAPTCHA token is generated and included in the signup request as captcha_token
  • The server verifies the token with Google using your secret key and checks the score against your threshold
  • Low-scoring submissions (likely bots) are rejected

reCAPTCHA works alongside the existing honeypot protection. The honeypot catches simple bots that fill in hidden fields, while reCAPTCHA catches more sophisticated automated submissions. Both protections can be active at the same time.

Available on all plans.

i
reCAPTCHA v3 is completely invisible to users — no checkboxes, no image puzzles. It scores visitors in the background based on their behavior.

SSRF Protection

All webhook URLs – custom webhooks, Slack incoming webhooks, and Discord webhooks – are validated when saved to your waitlist settings. Two rules are enforced:

  1. HTTPS required – only https:// URLs are accepted
  2. Private IP ranges blocked – requests to internal networks are rejected to prevent Server-Side Request Forgery (SSRF)

The following addresses and ranges are blocked:

  • localhost, 127.0.0.1, ::1
  • 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
  • 169.254.0.0/16 (link-local, including cloud metadata endpoints)

CORS Policy

Cross-Origin Resource Sharing (CORS) headers are set in server middleware on every response.

Endpoint type CORS policy
Public endpoints (/public/*) Wildcard Access-Control-Allow-Origin: * – allows the embed widget to work on any domain
Authenticated endpoints Restrictive CORS headers

This split ensures the embeddable signup widget works from any origin while keeping authenticated API routes locked down.

Domain Restrictions

i
Advanced Plan Required Domain restrictions require an Advanced plan or higher.

Waitlist owners can restrict which email addresses are allowed to sign up:

  • Allowed domains – limit signups to specific email domains (e.g., only @yourcompany.com)
  • Exclude personal emails – block personal email providers like Gmail, Yahoo, Hotmail, and others with the exclude_personal_emails setting

These restrictions are useful when you want to ensure only business or corporate email addresses can join your waitlist.

Data Residency & Encryption

Aspect Detail
Region United States (Oregon)
Encryption at rest AES-256 encryption on all stored data
Encryption in transit TLS 1.2+ enforced on all API endpoints
Data retention Data persists until explicitly deleted by the user or account owner

There is no automatic data expiration or audit log retention policy. All data remains in the database until a user deletes their signup, a waitlist owner deletes a record, or an account is deleted.

Data Protection

MakeEmWait follows a principle of minimizing what it handles directly:

Data type Handled by
Passwords Dedicated authentication service – never stored in application code or the database
Payment data Stripe – no credit card numbers touch MakeEmWait servers
Email delivery Resend – no email infrastructure to secure
API communication HTTPS enforced on all endpoints

Data Deletion

MakeEmWait provides three levels of data removal:

Unsubscribe from Emails

Signups can opt out of marketing emails (blasts) via a personalized unsubscribe link included in every email. The link contains an HMAC-SHA256 token that is verified server-side before processing the request. This prevents anyone from unsubscribing other people by guessing URLs.

Delete My Data

Signups can request full deletion of their record from the waitlist. This uses a separate endpoint with its own HMAC token – distinct from the unsubscribe token – so that one token type cannot be used for the other operation.

Account Deletion

Account owners can delete their entire account. This cascades to remove:

  • All waitlists owned by the account
  • All signups across those waitlists
  • The Stripe customer record
  • The authentication service user record

Token Security

All sensitive tokens use protections against forgery and timing attacks:

Token type Protection
Email verification Timing-safe comparison (crypto.timingSafeEqual)
Unsubscribe HMAC-SHA256 signature verification
Delete my data HMAC-SHA256 with a different prefix than unsubscribe tokens
Admin API key Timing-safe comparison (crypto.timingSafeEqual)

The use of different HMAC prefixes for unsubscribe and delete-my-data tokens ensures that a token generated for one operation cannot be reused for the other, even though both are signed with the same secret key.