---
title: How do I add password protection to my Vercel deployment?
description: Enable Password Protection on a Vercel deployment, configure automation and CORS bypasses, and verify the gate before your next CI run.
url: /kb/guide/add-password-protection-vercel-deployment
canonical_url: "https://vercel.com/kb/guide/add-password-protection-vercel-deployment"
last_updated: 2026-07-27
authors: Vercel
related:
  - /docs/deployment-protection
  - /docs/deployment-protection/methods-to-bypass-deployment-protection/trusted-sources
  - /kb/guide/how-to-enable-cors
  - /kb/guide/structure-your-application
  - /docs/deployment-protection/methods-to-protect-deployments/password-protection
  - /docs/deployment-protection/methods-to-bypass-deployment-protection/protection-bypass-automation
  - /docs/deployment-protection/automated-agent-access
  - /docs/deployment-protection/methods-to-bypass-deployment-protection/options-allowlist
install_vercel_plugin: npx plugins add vercel/vercel-plugin
---

Turning on Password Protection without configuring its bypasses in the same session breaks automation. CI jobs, webhooks from services like Stripe and Slack, and cross-origin browser requests start returning 401 because protection runs at Vercel's edge, before your application code. Enable protection and its bypasses together so those requests keep working.

Password Protection is available on Enterprise, or on Pro through the $150 per month Advanced Deployment Protection add-on. It isn't available on Hobby. If you're on Hobby, use the middleware alternative covered at the end of this guide.

This guide walks through what you need, how to turn protection on, how to keep automation and CORS working, how to verify the gate, and when to choose native protection over custom middleware.

## What you need to password-protect a Vercel deployment

Check your plan first, because the Password Protection toggle is plan-gated:

| Plan       | Password Protection                                                    | Notes                                                   |
| ---------- | ---------------------------------------------------------------------- | ------------------------------------------------------- |
| Hobby      | Not available                                                          | Use Vercel Authentication or the middleware alternative |
| Pro        | Available via the $150 per month Advanced Deployment Protection add-on | 30-day minimum before you can cancel the add-on         |
| Enterprise | Included by default                                                    | No add-on required                                      |

The Advanced Deployment Protection add-on bundles Password Protection, Private Production Deployments, and Deployment Protection Exceptions, and the $150 per month price covers the full bundle.

Next, decide how much to protect. Password Protection supports two scopes:

- **Standard Protection:** Covers every deployment except your production custom domain. Available on all plans.
  
- **All Deployments:** Covers every URL, including the production domain and generated `vercel.app` URLs. Available on Pro and Enterprise.
  

For an internal tool or a pre-launch site, choose All Deployments. If you only need previews kept private, Standard Protection is enough.

Protection runs at Vercel's edge, before your application code. It intercepts every request, including Routing Middleware, CORS preflights, server-to-server calls, and static file requests, before your route handlers run. The 401 errors covered later all follow from that edge-layer behavior.

## How to turn on Password Protection in the dashboard

You configure Password Protection in the same [Deployment Protection](https://vercel.com/docs/deployment-protection) settings where you set the scope. To turn it on:

1. From the Vercel [dashboard](https://vercel.com/dashboard), select your project.
   
2. Open **Settings**, then select **Deployment Protection**.
   
3. In the **Password Protection** section, use the toggle to turn it on. On Pro without the add-on, click **Enable and Pay** to add Advanced Deployment Protection first.
   
4. Select the deployment scope, Standard Protection or All Deployments.
   
5. Enter a password.
   
6. Select **Save**.
   

After you save, existing and future deployments require the password.

A few behaviors apply once protection is active:

- **Cookie persistence:** After a visitor enters the password, Vercel sets a cookie for that deployment URL so they aren't prompted again. Changing the password invalidates the cookie.
  
- **Disabling protection:** Turning the feature off makes all previously protected deployments public immediately, with no grace period.
  
- **Token scope:** The JWT set as a cookie is valid only for the URL it was issued on and can't be reused across different deployment URLs, even when they point to the same deployment.
  

Vercel enables Deployment Protection with Vercel Authentication by default on every new project. Password Protection extends that default to external stakeholders, such as clients and reviewers who don't have Vercel accounts.

### Configure Password Protection with the API

To manage protection programmatically or with Terraform, update the project's `passwordProtection` object through the Vercel API. Send the object with your chosen scope and password:

`{ "passwordProtection": { "deploymentType": "prod_deployment_urls_and_all_previews", "password": "your_password_here" } }`

The `deploymentType` field accepts `prod_deployment_urls_and_all_previews` for Standard Protection, `all` for All Deployments, and `preview` for preview deployments only. To disable protection, set the object to `null`:

`{ "passwordProtection": null }`

The dashboard and API produce the same result, so use whichever fits your workflow.

## How to keep automation working after you password-protect a deployment

Every protection method blocks all requests, including automated ones, so your CI jobs, tests, and webhooks return 401 the moment you turn protection on. Use Protection Bypass for Automation to let those requests through.

Protection Bypass for Automation works on all plans. Vercel injects the secret automatically as the `VERCEL_AUTOMATION_BYPASS_SECRET` system environment variable, so no setup is required. Send it as the `x-vercel-protection-bypass` header, or as a query parameter when a tool can't set custom headers. You can create multiple secrets per project, each with a label like `CI pipeline` or `Playwright tests`, so revoking one tool's access doesn't affect the others. Regenerating a secret invalidates existing deployments, so redeploy your project before the new value takes effect.

For end-to-end tests with Playwright, add the bypass header to every request:

`import { defineConfig } from '@playwright/test'; if (!process.env.VERCEL_AUTOMATION_BYPASS_SECRET) { throw new Error( 'VERCEL_AUTOMATION_BYPASS_SECRET is required to run tests against protected deployments', ); } export default defineConfig({ use: { baseURL: process.env.VERCEL_PREVIEW_URL, extraHTTPHeaders: { 'x-vercel-protection-bypass': process.env.VERCEL_AUTOMATION_BYPASS_SECRET, 'x-vercel-set-bypass-cookie': 'true', }, }, });`

The `x-vercel-set-bypass-cookie` header sets a cookie so in-browser navigation during the test doesn't trigger another challenge.

Cypress uses the same pattern split across its config and test files. Set the base URL and secret in the config:

`import { defineConfig } from 'cypress'; export default defineConfig({ e2e: { baseUrl: process.env.VERCEL_PREVIEW_URL, }, env: { BYPASS_SECRET: process.env.VERCEL_AUTOMATION_BYPASS_SECRET, }, });`

Then include the header on the first request in your test:

`cy.visit('/', { headers: { 'x-vercel-protection-bypass': Cypress.env('BYPASS_SECRET'), 'x-vercel-set-bypass-cookie': 'true', }, });`

Both tools now reach the protected deployment on every request.

For service-to-service calls, Trusted Sources is the recommended approach over long-lived secrets. Callers attach a short-lived OIDC token in the `x-vercel-trusted-oidc-idp-token` header, and Vercel verifies the signature with no shared secret to rotate. Forward the project's Vercel OIDC token in the request:

`import { getVercelOidcToken } from '@vercel/oidc'; await fetch('<https://protected-project.vercel.app/api/data>', { headers: { 'x-vercel-trusted-oidc-idp-token': await getVercelOidcToken() }, });`

The same pattern authorizes external providers such as GitHub Actions, which requests an ID token with `core.getIDToken()` and passes it in the same header. See [Trusted Sources](https://vercel.com/docs/deployment-protection/methods-to-bypass-deployment-protection/trusted-sources) for the full configuration.

If you're migrating from Netlify or Cloudflare, their access-control models don't map directly to Vercel's project-level bypass, so plan a custom bypass or a separate test path. Their equivalents are documented in [Netlify password protection](https://docs.netlify.com/manage/security/secure-access-to-sites/password-protection/) and [Cloudflare Access policies](https://developers.cloudflare.com/cloudflare-one/access-controls/policies/).

## How to fix CORS and other 401 errors after enabling password protection

Beyond automation, the most common 401 errors after you enable password protection come from cross-origin browser requests, server-side fetches, and external webhooks. These four patterns account for most of them.

### CORS preflight requests return 401

The browser blocks a cross-origin API call when its `OPTIONS` preflight returns 401 before your [CORS handling](https://vercel.com/kb/guide/how-to-enable-cors) runs. The edge intercepts every request, including preflights, and the browser can't attach the bypass header to a preflight. Turn on the OPTIONS Allowlist and add the path prefix, for example `/api`, so preflight requests to that prefix skip protection. Matching is prefix-based, so `/api` also covers `/api/v1/users`. After saving, the preflight returns a non-401 response and the real request proceeds.

### Server-side fetch calls return 401

A `fetch()` inside a Route Handler or Server Component that targets the deployment's absolute URL returns 401, because the server-to-server request reaches the edge without the visitor's authentication cookie. For client-side calls, use a relative path so the cookie is included automatically:

`fetch('/some/path');`

For server-side calls, forward the incoming request's cookies manually:

`const headers = { cookie: <incoming request header cookies> }; fetch('<incoming request origin>/some/path', { headers });`

Both approaches carry the authentication cookie, so the request resolves instead of hitting the gate.

### Webhooks from Stripe and Slack are blocked

External services can't carry the authentication cookie, so Stripe webhook deliveries return 401 and Slack event subscription verification fails. For services that let you set request headers, send the bypass secret as the `x-vercel-protection-bypass` header. For tools that only accept a URL, append it as a query parameter:

`https://your-app.vercel.app/api/webhooks/stripe?x-vercel-protection-bypass=your_bypass_secret_here`

Secrets in URLs are logged by proxies and CDNs, so prefer the header method whenever the service supports it.

### The authentication cookie doesn't carry across subdomains

A visitor authenticates on the preview domain, but XHR calls to an API subdomain still return 401, because the authentication cookie is scoped to the exact host instead of the parent domain. Keep API calls on the same origin with relative paths, or [co-locate your frontend and API](https://vercel.com/kb/guide/structure-your-application) under one project. Co-locating shares a deploy and rollback lifecycle, which is the tradeoff for keeping one origin.

## How to verify your deployment password protection is working

Run these checks right after saving to confirm the gate is closed:

1. **Test the password prompt.** Open the deployment URL in a private browser window. You should see the Vercel password screen, not your app. Entering the correct password sets the cookie and grants access for that deployment URL.
   
2. **Test the automation bypass.** Run `curl -H "x-vercel-protection-bypass: your_bypass_secret_here" <https://your-deployment.vercel.app`\> against the deployment. A 200 confirms the bypass works. A 401 means the request isn't authorized; if you regenerated the secret, redeploy so the deployment uses the new value.
   
3. **Test a CORS preflight.** Send a cross-origin `OPTIONS` request to a path on your allowlist and confirm a non-401 response. If the 401 persists, check that the allowlist prefix matches the actual path, since matching is prefix-based, not exact.
   

Confirm the scope covers what you expect. Past production deployment URLs like `my-project-main.vercel.app` are covered under All Deployments, while legacy Pre-Production Deployments leaves them public. If protecting historical URLs is a requirement, set the scope to All Deployments now.

## Why native Password Protection covers more than custom middleware

A `middleware.ts` file with Basic Auth logic is the common alternative to the add-on. It works for a personal project, but it can't reach the surfaces native protection covers.

Because Password Protection runs at the edge before any application code, it covers generated `vercel.app` URLs, past production deployment URLs, and static assets that application-layer middleware is blind to. Vercel enables Deployment Protection by default on new projects to close that coverage gap.

This table compares the two approaches:

| Surface                             | Custom middleware Basic Auth                                             | Native Password Protection                                                                       |
| ----------------------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------ |
| Static asset protection             | Often skips static asset paths unless the matcher is configured for them | Protects every request at the edge, including assets                                             |
| Shareable Links and access requests | No platform visibility into custom auth                                  | Work natively with the protection flow                                                           |
| Generated and past production URLs  | Requires a matcher covering all paths                                    | Configured at the project level, covering existing and future deployments per the selected scope |

On Hobby, or when you're not ready for the add-on, the middleware path is a documented workaround. Start with the [Basic Auth Password Protection template](https://vercel.com/templates/next.js/basic-auth-password) and configure the middleware matcher carefully, since common examples exclude paths such as `_next/static_`_,_ `next/image`, and `favicon.ico`. It trades edge-level coverage for zero platform cost, which is reasonable for a personal project and risky for staging data.

## Next steps

With protection and its bypasses configured, you're ready to apply this to a project. [Start a new Vercel project](https://vercel.com/new) and enable Deployment Protection in its settings, or [browse the templates](https://vercel.com/templates) for a framework-ready starting point.

## Related resources

- [Deployment Protection overview](https://vercel.com/docs/deployment-protection)
  
- [Password Protection](https://vercel.com/docs/deployment-protection/methods-to-protect-deployments/password-protection)
  
- [Protection Bypass for Automation](https://vercel.com/docs/deployment-protection/methods-to-bypass-deployment-protection/protection-bypass-automation)
  
- [Automated and agent access](https://vercel.com/docs/deployment-protection/automated-agent-access)
  
- [OPTIONS Allowlist](https://vercel.com/docs/deployment-protection/methods-to-bypass-deployment-protection/options-allowlist)
  
- [Trusted Sources](https://vercel.com/docs/deployment-protection/methods-to-bypass-deployment-protection/trusted-sources)
  

## Frequently asked questions

### Is Password Protection available on the Vercel Hobby plan?

No. Password Protection requires an Enterprise plan or the $150 per month Advanced Deployment Protection add-on on Pro. On Hobby, use Vercel Authentication with Standard Protection to restrict access to your team, or add the Next.js Basic Auth middleware template for a password gate without a Vercel account.

### Why does my CI pipeline return 401 after I enable Password Protection?

Password Protection runs at Vercel's edge and blocks every unauthenticated request, including automated ones, before your application code runs. Configure Protection Bypass for Automation, then send the generated secret as the `x-vercel-protection-bypass` header or query parameter. The `VERCEL_AUTOMATION_BYPASS_SECRET` environment variable is set automatically for use in your pipeline.

### Does Password Protection apply to my custom production domain?

Only under the All Deployments scope, which is available on Pro and Enterprise. The default Standard Protection scope covers preview deployments and generated deployment URLs but leaves your custom production domain publicly accessible. To gate the production domain with a password, select All Deployments when you configure the feature.

### What happens to existing deployments if I disable Password Protection?

Every previously protected deployment becomes publicly accessible immediately, with no grace period. Disabling the feature removes the password gate across all existing and future deployments for that project. If you re-enable it later, visitors must enter the password again, and any previous access cookies no longer apply.

### Can I use Password Protection and Vercel Authentication at the same time?

Yes. The two methods are compatible and can run together on the same project. Password Protection covers external stakeholders without Vercel accounts, while Vercel Authentication restricts access to your Vercel team members. On the Enterprise plan, you can layer Trusted IPs on top of both for IP-based restriction.