Browse the manual

Security

How Made with Pepper protects your data and sessions, including HTTP security headers, session timeouts, and environment configuration.

On this page

Made with Pepper ships with security defaults that protect your installation against common web vulnerabilities. Some protections use defaults. The owner configures sign-in policy in Settings > Security. Server administrators manage HTTPS and environment settings.

Profile page with personal information, language and sign-in security

HTTP security headers

Made with Pepper adds these headers to responses that pass through its security middleware. HSTS requires HTTPS, and CSP requires a configured policy:

Header Value Purpose
X-Frame-Options SAMEORIGIN Prevents clickjacking by blocking other sites from loading the app in an iframe
X-Content-Type-Options nosniff Prevents browsers from MIME-sniffing a response away from the declared content type
Referrer-Policy strict-origin-when-cross-origin Limits referrer information sent to external sites
Permissions-Policy camera=(), microphone=(), geolocation=() Disables browser APIs that Made with Pepper does not use
Strict-Transport-Security max-age=31536000; includeSubDomains Tells browsers to always use HTTPS (only sent on secure connections)
Content-Security-Policy Restrictive default (see below) Controls which resources the browser may load

HSTS (HTTP strict transport security)

Made with Pepper adds HSTS only when the request arrives over HTTPS. This prevents breaking development environments that use HTTP. The max-age defaults to one year (31,536,000 seconds).

To change the HSTS duration, add to your .env:

SECURITY_HSTS_MAX_AGE=86400

Content security policy (CSP)

The default CSP allows scripts, styles, images, and fonts from your own domain only. The policy permits inline scripts and styles for error pages and the theme script. Interactive screens use React. The React pages load their scripts and their bundled fonts from your own domain too, so the default policy covers them.

Default policy:

default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'none'

To customise or disable the CSP, add to your .env:

# Custom policy
SECURITY_CSP="default-src 'self'; script-src 'self' 'unsafe-inline'"

# Disable CSP entirely
SECURITY_CSP=

Session idle timeout

Made with Pepper logs out users after 30 minutes of inactivity by default. This is separate from Laravel's session lifetime, which controls how long session data can remain idle before it expires.

When the idle timeout expires, Made with Pepper redirects the user to the sign-in page with a message explaining that their session expired.

Remember me

The login page has a Remember me checkbox. When checked:

  • The user's session bypasses the idle timeout. Made with Pepper will not log them out for inactivity.
  • Laravel's session lifetime still applies to session data. Requests refresh its expiry.
  • The browser stores a long-lived remember cookie. If session data expires, Made with Pepper can restore sign-in from a current remember cookie. Deactivation, password changes, password resets, role changes and ownership transfers revoke old sign-ins and remembered credentials. Reactivation requires a fresh sign-in.

When not checked:

  • The idle timeout applies. Made with Pepper logs the user out after the configured number of minutes without any requests.
  • Closing the browser may end the session (depending on the browser's cookie handling).

Recommendation for shared or public computers: Do not check "Remember me". The idle timeout provides automatic protection against unattended sessions.

Configuring the idle timeout

Add to your .env:

# Set idle timeout to 60 minutes
SESSION_IDLE_TIMEOUT=60

# Disable idle timeout for all sessions (rely on session lifetime only)
SESSION_IDLE_TIMEOUT=0

Session lifetime

Set Laravel's session lifetime (minutes of inactivity before session data expires) with this variable:

# Default: 120 minutes
SESSION_LIFETIME=120

For sessions without "Remember me", the shorter idle limit applies. Active requests refresh session expiry. Remembered sessions bypass the Made with Pepper idle timeout, and Laravel can restore sign-in from the remember cookie after session data expires.

Session cookies

Made with Pepper uses Laravel's default session cookie settings:

Setting Default Purpose
httponly true Prevents JavaScript from reading the session cookie
samesite lax Limits cross-site cookie sending
secure auto Cookies are secure-only when accessed over HTTPS

Check these settings against your hosting setup.

Rate limiting

Made with Pepper limits login attempts to prevent brute-force attacks:

  • Login: 5 attempts per minute per email address
  • Password reset: 3 requests per hour
  • Installer possession proof: five failed token attempts per minute for each session and source IP

Login and password-reset errors show the wait before another attempt. If installer token attempts reach the limit, wait one minute before trying again.

Shared hosting

Made with Pepper includes security defaults for shared hosting. Check HTTPS, response headers and session behavior on your host.

If your host uses a reverse proxy (Cloudflare, nginx proxy, load balancer), Made with Pepper adds HSTS only when Laravel identifies the request as secure. Check the response header over HTTPS and ask your host to check the proxy setup if HSTS is missing. A proxy may set its own HSTS header; do not assume it does.

If your host forces HTTP and you cannot enable HTTPS, Made with Pepper skips HSTS. The other security headers (CSP, X-Frame-Options, etc.) still apply.

The web server must be able to write to storage/. Made with Pepper stores session files, logs, and uploaded attachments here. On most shared hosts, permissions of 755 or 775 work.

Troubleshooting sessions

I keep getting logged out

If Made with Pepper logs you or your users out when you do not expect it:

  1. Use "Remember me". If you check "Remember me" when logging in, the session bypasses the idle timeout. This is the simplest fix for users on private computers.

  2. Increase the idle timeout. The default is 30 minutes. If users are idle for longer than this without "Remember me", Made with Pepper logs them out. Increase it in .env:

    SESSION_IDLE_TIMEOUT=60
    
  3. Increase the session lifetime. This controls how long session data can remain idle (default: 120 minutes). Active requests refresh the expiry. Increase it:

    SESSION_LIFETIME=240
    
  4. Check Laravel session storage on shared hosts. Laravel manages its file-session expiry through SESSION_LIFETIME; PHP's session.gc_maxlifetime does not set this limit. Ask your host whether a separate cleanup job removes files from storage/framework/sessions/.

  5. Disable the idle timeout. To turn off the idle timeout for all users:

    SESSION_IDLE_TIMEOUT=0
    

Users stay logged in longer than expected

If users remain logged in for longer than you want:

  • Verify "Remember me" behavior. Users who check "Remember me" bypass the idle timeout. A shorter SESSION_LIFETIME expires session data sooner, but Laravel can restore sign-in from the remember cookie.
  • Check session lifetime. The session lifetime (default: 120 minutes) controls idle session-data expiry. Active requests refresh it; it does not impose an absolute sign-in duration.

Sessions not persisting across page loads

If the app loses sessions on every request:

  • Verify storage/framework/sessions/ is writable by the web server.
  • Verify APP_KEY is set in .env (the installer sets this automatically).
  • Verify your web server points to the public/ directory, not the project root.

Permissions

See Roles and permissions for access control details.

Two-factor sign-in

Each person can set up two-factor sign-in from Your profile > Security.

  1. Click Set up two-factor.
  2. Scan the code with an authenticator app, or enter the displayed setup key there.
  3. Enter the Six-digit code from that app.
  4. Click Turn on.
  5. Store the displayed Recovery codes in a private, safe place.

Recovery codes appear once. Each code works once. New recovery codes replace the earlier set.

The owner can select Require two-factor sign-in in Settings > Security. The owner must first set up their own two-factor sign-in. When required, people cannot turn it off themselves.

Single sign-on

The owner can configure an OpenID Connect provider in Settings > Security. SSO signs in existing accounts; it does not create accounts automatically.

  1. Register the displayed Redirect URL to register at your provider with the provider.
  2. Enter Button name, Issuer URL and Client ID.
  3. Enter the provider's Client secret.
  4. Set Allowed email domains when a domain restriction is needed.
  5. Enable Single sign-on.
  6. Click Save changes.

Keep existing owner access until you have tested the provider. Follow the provider's setup instructions. These settings do not replace roles or guest scopes.

Signed-in devices

Your profile > Security lists Signed-in devices, their last activity and sign-in method. The current device is marked.

Use Sign out on another device to end that session. Sign out other devices keeps the current session. Review unfamiliar entries before continuing work. No passkey setup is available.

Need help with the product?

Contact support