Skip to content
Introduction Price $49 −$20
ESC

Searching...

Quick Links

Type to search • Press to navigate • Enter to select

Keep typing to search...

No results found

No documentation matches ""

Security.

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

Jun 3, 2026

Security

InvoiceScript ships with security defaults that protect your installation against common web vulnerabilities. All security settings are applied automatically and can be adjusted via environment variables.

HTTP security headers

Every response from InvoiceScript includes the following security headers:

Header Value Purpose
X-Frame-Options SAMEORIGIN Prevents clickjacking by blocking the app from being loaded in an iframe on another site
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 InvoiceScript 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)

HSTS is only added 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. Inline scripts and styles are permitted because Alpine.js and Blade templates require 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

InvoiceScript logs out users after 30 minutes of inactivity by default. This is separate from Laravel's session lifetime, which controls the absolute maximum session duration.

When the idle timeout expires, the user is redirected 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. They will not be logged out for inactivity.
  • The session still respects Laravel's absolute session lifetime.
  • The browser stores a long-lived remember cookie. If the session file expires, Laravel re-authenticates the user from this cookie automatically.

When not checked:

  • The idle timeout applies. After the configured number of minutes without any requests, the user is logged out.
  • 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

Laravel's session lifetime (the absolute maximum session duration regardless of activity) is set separately:

# Default: 120 minutes
SESSION_LIFETIME=120

The idle timeout and session lifetime work together. Whichever expires first will end the session. Remembered sessions are exempt from idle timeout but still respect the session lifetime.

Session cookies

InvoiceScript 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

These defaults follow industry best practices and do not normally need adjustment.

Rate limiting

Login attempts are limited to prevent brute-force attacks:

  • Login: 5 attempts per minute per email address
  • Password reset: 3 requests per hour
  • Installer: 10 requests per hour

When the limit is reached, the user sees a message indicating how many seconds to wait.

Shared hosting

InvoiceScript's security features work on shared hosting without special configuration. The defaults are safe out of the box.

If your host uses a reverse proxy (Cloudflare, nginx proxy, load balancer), the HSTS header is still sent correctly because it only activates when the request arrives over HTTPS. Most shared hosts terminate HTTPS at the proxy and forward to the app as HTTP, so HSTS is handled by the proxy layer. No InvoiceScript configuration is required.

If your host forces HTTP and you cannot enable HTTPS, HSTS is silently skipped. The other security headers (CSP, X-Frame-Options, etc.) still apply.

The storage/ directory must be writable by the web server. InvoiceScript 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 you or your users are being logged out unexpectedly:

  1. Use "Remember me". If you check "Remember me" when logging in, the idle timeout is bypassed entirely. 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", they are logged out. Increase it in .env:

    SESSION_IDLE_TIMEOUT=60
    
  3. Increase the session lifetime. This is the absolute maximum session duration (default: 120 minutes). Even active users are logged out after this time. Increase it:

    SESSION_LIFETIME=240
    
  4. Check PHP session configuration on shared hosts. Some shared hosts set aggressive session.gc_maxlifetime values in PHP configuration (e.g. 24 minutes). If this value is lower than your SESSION_LIFETIME, PHP garbage collection may destroy the session file before InvoiceScript expects it to expire. Ask your host to raise session.gc_maxlifetime to at least match your SESSION_LIFETIME.

  5. Disable the idle timeout entirely. If idle timeout is not desired for any user:

    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. This is by design. If you need all sessions to expire after inactivity regardless of "Remember me", set a shorter SESSION_LIFETIME instead — this applies to all sessions.
  • Check session lifetime. The session lifetime (default: 120 minutes) is the hard ceiling. Lower it if needed.

Sessions not persisting across page loads

If sessions are lost 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.

Ready to build?

One-time purchase. Self-hosted. Own every file forever.

Get InvoiceScript