# SvelteKit Password Protect

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.

## Features

- 🔒 Password-protect your entire SvelteKit app or specific routes
- 🧠 In-memory or JWT-based session management
- ⚡️ Simple API, easy integration
- 🛡️ CSRF protection and rate limiting

## This package is not

- A Replacement for your authentication or authorization layer

## Installation

```bash
npm install sveltekit-password-protect
# or
pnpm add sveltekit-password-protect
```

## Quick Start

1. **Add the handler to your `src/hooks.server.ts`:**

```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)`
```

2. **Start your SvelteKit app.**  
   Your site is now password protected!

## Configuration

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:**

- **CSRF protection (`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 envirements

## Example

```ts
export 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'
});
```

## Customizing the Password Page

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.

### Example

```ts
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>
  `;
 }
});
```

#### Props available in `getPasswordFormPage`

- `title`: The title for the password page
- `description`: The description for the password page
- `error`: Any error message to display
- `csrfToken`: The CSRF token (if enabled)
- `redirect`: The redirect path after login
- `defaultOptions`: The options passed to the handler

> **Note:** This is the only supported way to customize the UI. All other UI aspects are fixed.

## Security Notes

- **Never commit your password or secrets to version control.** Use environment variables.
- This is a simple protection layer, not a replacement for full authentication in production.
- Your website can still have an authentication layer, this package is completely independent from all your website logic and won't interfere.

## Contributing

Contributions, issues, and feature requests are welcome!  
Feel free to open an issue or submit a pull request.

## License

MIT © 2025 [humanshield85](https://github.com/humanshield89)
