Skip to main content
Documentation
Concepts

Password Protection

How to protect a WarpLink link with a password, with server-side validation that gates the redirect until the correct password is entered.

WarpLink supports password-protected links that require users to enter a password before being redirected to the destination.

How It Works

The entire password flow happens at the edge, with no round-trip to the origin server:

  1. User clicks a password-protected WarpLink URL
  2. WarpLink detects that the link has a password set
  3. WarpLink serves an HTML form asking for the password
  4. User enters the password and submits the form
  5. WarpLink hashes the submitted password and compares it to the stored hash
  6. Match: User is redirected to the destination via 302
  7. No match: The form is re-displayed with an error message

Server-Side Validation

Password validation is entirely server-side:

  • Passwords are stored as hashes in the link configuration (never in plaintext)
  • The comparison happens server-side at the edge
  • No client-side JavaScript is needed for validation
  • The password is submitted via an HTML form POST

This means the password flow works even with JavaScript disabled.

Setting a Password

Set a password when creating or updating a link via the API:

Or set it in the dashboard when creating or editing a link.

Removing a Password

Update the link and set the password to null:

GET /v1/links/resolve/{slug} refuses a password-protected link with 403 PASSWORD_REQUIRED and returns no destination and no platform URLs. The password is checked in the browser, so handing the destination to an API caller or to an app would defeat the protection. A refusal records no click.

Send the user to the short URL itself. The password form is served there, and a correct password redirects on to the destination.

SDK 1.1.0 and later surface the refusal as a named error: WarpLinkError.passwordRequired on iOS, WarpLinkError.PasswordRequired on Android, E_PASSWORD_REQUIRED on React Native, and WarpLinkPasswordRequiredException on Flutter. Handle it by opening the tapped URL in a browser.

Behavior with Bots

Social media bots that crawl password-protected links receive the OG/Twitter Card metadata without needing the password. The social preview is still generated. Only the redirect to the final destination requires the password.

Behavior

  • Password-protected links open in the browser, and resolving one through the API or an SDK returns PASSWORD_REQUIRED.
  • Each link has one password, shared by everyone who has it.

How the Password Hash Actually Works

Setting a password doesn't store the password itself, and it doesn't store a single fixed hash either. When a password is set, WarpLink generates a random salt, then derives a key from the password and that salt using PBKDF2 with SHA-256 and 100,000 iterations, and stores the salt and the derived key together as one string. A salted, iterated hash like this is deliberately slow to compute: 100,000 iterations costs roughly 10 to 20 milliseconds of native cryptographic work per attempt on typical hardware, which is irrelevant to a legitimate visitor entering a password once, but makes brute-forcing a stolen hash by trying many candidate passwords meaningfully more expensive than a single unsalted hash would be. That cost is also isolated to the rare password form submission itself, never to the redirect hot path that every other link takes.

Verification supports every hash format WarpLink has stored, so older links keep working. Whichever format applies, the comparison between the freshly computed hash and the stored one runs in constant time rather than stopping at the first mismatched character, which closes off a timing side-channel that a naive string comparison would otherwise leave open.

When to Use

A password gates the destination, not the fact that a link exists or what it looks like when shared, so it fits situations where you want to limit who can follow a link without hiding that a link was sent. Common cases: an early-access build shared with a waitlist before public launch, an internal document or dashboard passed outside a team's normal auth system, or a time-limited offer you want gated at the link rather than behind a separate login. It's a lightweight, no-account-required gate for sharing a link with a chosen audience.

Worked Example

Setting a password on link creation, then what a visitor experiences:

A visitor who opens the short link in a browser gets the HTML form, not a redirect:

Submitting the wrong password re-renders the same form with an inline error and no redirect:

The correct password produces the same 302 any unprotected link would:

Trying to resolve the same link through the API, rather than opening it in a browser, is refused outright regardless of whether you know the password, since the API has no form to collect it through:

Troubleshooting

The password form keeps rejecting a password I'm sure is correct. Passwords are compared exactly, including case and any trailing whitespace copied along with it. Retype it directly rather than pasting from a source that might carry extra characters.

A custom domain's password-protected link 404s instead of showing the form. Check the domain's own status first. A suspended custom domain (for example, one whose free trial ended) returns the same not-found response the password form's own POST handler checks for, deliberately indistinguishable from an unknown link, before the password logic ever runs. See custom domains.

I removed the password but the link still asks for one. Confirm the update request actually set "password": null and returned success, rather than omitting the field (which leaves the existing password untouched). Setting it to an empty string is not the same as clearing it.

FAQ

Can different users have different passwords for the same link? No. A password is set once per link and shared by everyone who has it.

Is the password ever sent to WarpLink's servers in plaintext? It's submitted over HTTPS as an ordinary form POST, hashed on receipt, and never stored in plaintext or logged.

Can a password-protected link still show a social preview when shared? Yes. See Behavior with Bots above: crawlers get the Open Graph card without needing the password, since a preview doesn't grant access to the destination.

Why can't I deep link a password-protected link into my app? Password-protected links open in the browser so the visitor can enter the password, and resolving one through an SDK or the API returns PASSWORD_REQUIRED instead of a destination.

Does changing a link's password invalidate sessions for people who already entered the old one? There's no session at all. Every visit re-checks the password against whatever is currently stored, so changing it takes effect on the very next request, for everyone.