Skip to main content
Proper security configuration is critical for protecting your NetBird network infrastructure. This guide covers all security-related environment variables and configuration options.

Environment Variables

Authentication & Authorization

NETBIRD_ALLOWED_DOMAIN

Purpose: Restrict access to users from a specific email domain
NETBIRD_ALLOWED_DOMAIN=example.com
Strongly recommended for production. Without this setting, any user with a valid Google account can authenticate and access your VPN management interface.
Behavior:
  • Enforced during OAuth callback after successful Google authentication
  • Case-insensitive domain matching
  • Users with non-matching domains are rejected with a clear error message
  • Existing users with non-matching domains can still access if already registered
// Source: config/netbird.php:12
'allowed_domain' => env('NETBIRD_ALLOWED_DOMAIN'),

// Source: app/Http/Controllers/Auth/GoogleController.php:24-31
$allowedDomain = config('netbird.allowed_domain');
if ($allowedDomain) {
    $emailDomain = substr(strrchr($googleUser->getEmail(), '@'), 1);
    if (strcasecmp($emailDomain, $allowedDomain) !== 0) {
        return redirect()->route('login')
            ->withErrors(['email' => 'Only users with @'.$allowedDomain.' email addresses are allowed.']);
    }
}

NETBIRD_ADMIN_EMAIL

Purpose: Define the administrator email address
NETBIRD_ADMIN_EMAIL=admin@example.com
Admin Privileges:
  • Approve or deny resource requests
  • Create resources without approval
  • Edit and delete any resource
  • View activity logs
  • Manage all pending requests
Only one admin email is supported. For multiple admins, consider implementing role-based access control or granting elevated NetBird API permissions to multiple users.

API Security

NETBIRD_API_TOKEN

Purpose: Authenticate with the NetBird API
NETBIRD_API_TOKEN=nb_1234567890abcdef
Critical Security CredentialThis token has full access to your NetBird network. Compromise of this token could allow an attacker to:
  • Create, modify, or delete network resources
  • Access network configuration
  • Potentially expose customer networks
Protection measures:
  • Never commit to version control
  • Use different tokens for dev/staging/production
  • Rotate regularly (every 90 days recommended)
  • Store in secure secrets management system
  • Monitor API usage for anomalies
Configuration Reference:
// Source: config/netbird.php:5
'api_token' => env('NETBIRD_API_TOKEN'),

NETBIRD_API_URL

Purpose: NetBird API endpoint URL
NETBIRD_API_URL=https://api.netbird.io
  • Use official NetBird API URL or your self-hosted instance
  • Must use HTTPS in production
  • Default: https://api.netbird.io

Session Configuration

SESSION_DRIVER

Purpose: Session storage backend
SESSION_DRIVER=database
Recommended: database (default) Options:
  • database - Best for production (scalable, persistent)
  • redis - High-performance option for large deployments
  • file - Development only (not scalable)
  • cookie - Not recommended (security implications)
Database sessions provide the best balance of security, performance, and reliability for most deployments.

SESSION_LIFETIME

Purpose: Session idle timeout in minutes
SESSION_LIFETIME=120
Default: 120 minutes (2 hours) Security considerations:
  • Shorter lifetime = better security, more frequent re-authentication
  • Longer lifetime = better UX, higher session hijacking risk
  • Recommended range: 60-240 minutes
Balance security with user experience. For high-security environments, consider 60 minutes. For general use, 120 minutes is appropriate.
Purpose: Require HTTPS for session cookies
SESSION_SECURE_COOKIE=true
Required in production. Always set to true when using HTTPS. This prevents session cookies from being transmitted over unencrypted connections.
// Source: config/session.php:172
'secure' => env('SESSION_SECURE_COOKIE'),

SESSION_HTTP_ONLY

Purpose: Prevent JavaScript access to session cookies
SESSION_HTTP_ONLY=true
Default: true Leave enabled - This is critical XSS protection. There is no legitimate reason to disable this.

SESSION_SAME_SITE

Purpose: CSRF protection via SameSite cookie attribute
SESSION_SAME_SITE=lax
Default: lax Options:
  • lax (recommended) - Balances security and compatibility
  • strict - Maximum security, may break OAuth flows
  • none - Not recommended (requires secure=true)

SESSION_ENCRYPT

Purpose: Encrypt session data
SESSION_ENCRYPT=false
Default: false
Encryption adds overhead but provides defense-in-depth. Enable if storing sensitive data in sessions or if compliance requires it.

OAuth Configuration

Google OAuth (Example)

GOOGLE_CLIENT_ID=123456789-abc.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-abc123def456
GOOGLE_REDIRECT_URI=https://your-domain.com/auth/google/callback
OAuth Security Requirements:
  • Keep GOOGLE_CLIENT_SECRET confidential
  • Use separate OAuth apps for dev/staging/production
  • Whitelist only necessary redirect URIs in Google Console
  • Enable domain restrictions in Google OAuth consent screen if possible
  • Monitor OAuth app usage in Google Console
Redirect URI Configuration:
  • Must exactly match the URI registered in Google Cloud Console
  • Must use HTTPS in production
  • Cannot use wildcards
  • Each environment needs its own redirect URI

Application Security

APP_ENV

Purpose: Application environment
APP_ENV=production
Critical: Always set to production in production. This disables debug mode and enables security features.

APP_DEBUG

Purpose: Enable/disable debug mode
APP_DEBUG=false
Must be false in production. Debug mode exposes:
  • Database queries and credentials
  • Application source code paths
  • Environment variables
  • Stack traces with sensitive information

APP_KEY

Purpose: Application encryption key
APP_KEY=base64:abc123def456...
Generated by: php artisan key:generate
Critical Security Key
  • Used for all encryption in Laravel
  • Changing this invalidates existing sessions and encrypted data
  • Never share or commit to version control
  • Back up securely before rotation

APP_URL

Purpose: Application base URL
APP_URL=https://vpn-selfservice.example.com
Production requirements:
  • Must use HTTPS (not HTTP)
  • Should match your actual domain
  • Used for generating OAuth callback URLs and email links
  • Include port if non-standard (e.g., https://example.com:8443)

Production Security Configuration

Minimal Secure Configuration

# Application
APP_NAME="VPN Selfservice"
APP_ENV=production
APP_DEBUG=false
APP_KEY=base64:your-generated-key
APP_URL=https://vpn.example.com

# Database (use strong credentials)
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=netbird_production
DB_USERNAME=netbird_user
DB_PASSWORD=<strong-random-password>

# Session Security
SESSION_DRIVER=database
SESSION_LIFETIME=120
SESSION_SECURE_COOKIE=true
SESSION_HTTP_ONLY=true
SESSION_SAME_SITE=lax

# OAuth (Production credentials)
GOOGLE_CLIENT_ID=<production-client-id>
GOOGLE_CLIENT_SECRET=<production-client-secret>
GOOGLE_REDIRECT_URI=https://vpn.example.com/auth/google/callback

# NetBird Configuration
NETBIRD_API_URL=https://api.netbird.io
NETBIRD_API_TOKEN=<production-api-token>
NETBIRD_NETWORK_ID=<your-network-id>
NETBIRD_ADMIN_EMAIL=admin@example.com
NETBIRD_ALLOWED_DOMAIN=example.com  # CRITICAL

# Logging
LOG_CHANNEL=stack
LOG_LEVEL=warning

Configuration Checklist

Before going live:
  • APP_ENV=production
  • APP_DEBUG=false
  • APP_KEY generated and unique
  • APP_URL uses HTTPS
  • NETBIRD_ALLOWED_DOMAIN configured
  • NETBIRD_ADMIN_EMAIL set to trusted user
  • NETBIRD_API_TOKEN is production token
  • SESSION_SECURE_COOKIE=true
  • SESSION_HTTP_ONLY=true
  • Strong database password
  • OAuth production credentials
  • OAuth redirect URI uses HTTPS
  • .env file has proper permissions (600)
  • .env excluded from version control
  • Web server configured for HTTPS
  • Firewall rules configured
  • Database backups enabled
  • Log monitoring configured

Testing Security Configuration

Verify HTTPS Enforcement

# Should redirect to HTTPS
curl -I http://your-domain.com

# Should return 200 OK
curl -I https://your-domain.com

Verify Domain Restriction

  1. Attempt login with non-allowed domain email
  2. Should be rejected with error message
  3. Check error appears at post-OAuth step

Verify Session Security

Inspect session cookie in browser dev tools:
  • Secure flag should be true
  • HttpOnly flag should be true
  • SameSite should be Lax

Verify Admin Access

  1. Login as admin user (matching NETBIRD_ADMIN_EMAIL)
  2. Verify “Pending Approvals” section appears
  3. Verify ability to approve/deny requests
  4. Logout and login as non-admin
  5. Verify approval section is hidden

Troubleshooting

”CSRF token mismatch” errors

Cause: Session configuration issues Solutions:
  • Verify SESSION_DOMAIN matches your actual domain
  • Check SESSION_SECURE_COOKIE is correct for your protocol
  • Clear browser cookies and retry
  • Run php artisan config:clear

OAuth redirect errors

Cause: Mismatch between configured and registered URIs Solutions:
  • Verify GOOGLE_REDIRECT_URI exactly matches Google Console
  • Ensure using HTTPS in production
  • Check for trailing slashes (must match exactly)
  • Verify OAuth app is not in testing mode with limited users

Users bypassing domain restriction

Cause: Users registered before restriction was configured Solution:
-- Remove users not matching allowed domain
DELETE FROM users WHERE email NOT LIKE '%@example.com';
This will permanently delete user data. Back up first and notify affected users.

Next Steps

Overview

Return to security overview

Best Practices

Learn security best practices