A simple, plug-and-play password protection middleware for SvelteKit apps. Perfect for freelancers, agencies, or anyone needing to quickly secure a SvelteKit site with a password—ideal for demos, staging, or sensitive previews.
npm install sveltekit-password-protect
# or
pnpm add sveltekit-password-protect
src/hooks.server.ts
:import { createPasswordProtectHandler } from 'sveltekit-password-protect';
import type { Handle } from '@sveltejs/kit';
export const handle: Handle = createPasswordProtectHandler({
// put this in an envirement variable and use it here,
password: 'your-password'
// jwtSecret is optional. If provided, JWT sessions will be used instead of in-memory sessions.
// jwtSecret: 'your-jwt-secret',
// csrf is disabled by default becasue it is not compatible in serverless envirements
// enableCSRF: true,
});
// If you have multiple handlers, use `sequence(handler1,handler2)`
You can customize the handler with the following options:
Option | Type | Required | Default | Description |
---|---|---|---|---|
password |
string | Yes | — | The password required to access the site |
jwtSecret |
string | No | undefined | If provided, enables JWT session storage |
sessionTTL |
number | No | 12 hours | Session time-to-live (milliseconds) |
csrfTokenTTL |
number | No | 5 minutes | CSRF token time-to-live (milliseconds) |
cookieName |
string | No | 'spw' | Name of the session cookie |
title |
string | No | 'Protected' | Title for the password page |
description |
string | No | '' | Description for the password page |
redirect |
string | No | '/' | Redirect after successful login |
path |
string | No | '/' | Path to protect |
cacheAdapter |
object | No | InMemory | Custom cache/session adapter |
maxFailedCalls |
number | No | 5 | Max failed attempts before rate limiting |
rateLimitTTL |
number | No | 1 minute | Rate limit window (milliseconds) |
enableCSRF |
boolean | No | false | Enable CSRF protection for login/logout |
Note:
enableCSRF
) is not compatible with serverless environments. If you deploy to a serverless platform (e.g., Vercel, Netlify, Cloudflare), enabling CSRF will break login/logout functionality. Only use this option in traditional server environments. or if you provide your own cache adapter that supports serverless envirementsexport const handle: Handle = createPasswordProtectHandler({
password: process.env.PASSWORD,
// jwtSecret: process.env.JWT_SECRET, // Optional
title: 'You shall not pass',
description: 'Say the magic word.',
// the user will be redirected to the last page he was on or to this path specified here
redirect: '/dashboard'
});
While the default UI is minimal and not customizable via options, you can provide your own password form page by supplying a getPasswordFormPage
function. This function receives a set of props and should return a string of HTML to be rendered as the password page.
import { createPasswordProtectHandler, type TemplatePageProps } from 'sveltekit-password-protect';
export const handle = createPasswordProtectHandler({
password: process.env.PASSWORD,
getPasswordFormPage: (props: TemplatePageProps) => {
return `
<form action="${props.defaultOptions.path}" method="post">
<h1>${props.title}</h1>
<p>${props.description}</p>
<p>${props.error}</p>
<input type="password" name="password" />
<input type="hidden" name="csrfToken" value="${props.csrfToken}" />
<input type="hidden" name="redirect" value="${props.redirect}" />
<button type="submit">Login</button>
</form>
`;
}
});
getPasswordFormPage
title
: The title for the password pagedescription
: The description for the password pageerror
: Any error message to displaycsrfToken
: The CSRF token (if enabled)redirect
: The redirect path after logindefaultOptions
: The options passed to the handlerNote: This is the only supported way to customize the UI. All other UI aspects are fixed.
Contributions, issues, and feature requests are welcome!
Feel free to open an issue or submit a pull request.
MIT © 2025 humanshield85