Skip to content

Security & Validation ​

LaraCommerce is built with enterprise-grade security in mind. This page details the built-in security features, middleware, and request validation mechanisms.


Global Middleware ​

Every API request passes through a series of global middlewares configured in bootstrap/app.php:

1. ForceJsonResponse ​

Automatically intercepts all requests (even those without the Accept: application/json header) and ensures that the API always returns a properly formatted JSON response. This prevents HTML error pages from leaking into client applications.

2. SecurityHeaders ​

Adds crucial HTTP security headers to every response to protect against XSS, clickjacking, and other common web vulnerabilities:

  • X-Frame-Options: DENY
  • X-XSS-Protection: 1; mode=block
  • X-Content-Type-Options: nosniff
  • Strict-Transport-Security: max-age=31536000; includeSubDomains
  • Referrer-Policy: strict-origin-when-cross-origin
  • Cache-Control: no-store, must-revalidate
  • Pragma: no-cache
  • Server identification headers (X-Powered-By, Server) are removed.

3. Rate Limiting (throttle) ​

LaraCommerce uses Redis-backed rate limiting in production to prevent brute-force and DDoS attacks.

  • Global API (throttle:api): 60 requests per minute.
  • Auth Routes (throttle:auth): 10 requests per minute (Login, Register).
  • Strict Routes (throttle:strict): 5 requests per minute (Password reset, Returns).

Authentication & Authorization ​

Sanctum Tokens ​

The API uses Laravel Sanctum for stateful SPA authentication or token-based API authentication. We implement a dual-token system:

  1. Access Token: Short-lived, used for all protected endpoints.
  2. Refresh Token: Long-lived, used to obtain a new access token without re-authenticating.

Route Protection Aliases ​

Specific routes are protected using middleware aliases:

  • check.active: Ensures the authenticated user's account is not suspended (is_active = true). If suspended, returns a 403 Forbidden.
  • email.verified: Requires the user to have verified their email before accessing sensitive routes (e.g., placing an order, payments).

Role-Based Access Control (RBAC) ​

We utilize Spatie Laravel Permission to handle complex authorization.

  • Roles: customer, manager, admin.
  • Permissions: 57 granular permissions (e.g., view orders, edit products, manage settings).
  • Middleware applied to admin routes: middleware(['auth:sanctum', 'role:admin']).

Validation & Exception Handling ​

Form Requests ​

Incoming data is strictly validated using Laravel Form Requests (e.g., StoreProductRequest, UpdateUserRequest). Invalid data automatically triggers a 422 Unprocessable Entity response with a structured error payload.

Model Validation On Save (ValidatesOnSave) ​

As a second layer of defense, a custom trait (ValidatesOnSave) is applied to Eloquent models. This ensures that even if data is modified programmatically outside of a controller, it must pass the model's validation rules before being saved to the database.

Centralized Exception Handler ​

The API features a custom exception handler in bootstrap/app.php that intercepts all exceptions and normalizes them into a consistent JSON format.

json
// Example of a normalized 403 response
{
  "status": "error",
  "message": "Forbidden. Insufficient permissions.",
  "code": "FORBIDDEN"
}

Exceptions handled specifically:

  • ValidationException -> 422
  • ModelValidationException -> 422
  • SpatieUnauthorizedException -> 403
  • AuthenticationException -> 401
  • NotFoundHttpException -> 404
  • MethodNotAllowedHttpException -> 405

Webhook Security ​

Stripe Signature Verification ​

All incoming Stripe webhooks are verified using \Stripe\Webhook::constructEvent() with the STRIPE_WEBHOOK_SECRET environment variable. If the secret is not configured, webhooks are rejected with a logged error. Invalid signatures return 400 Bad Request.

Event Deduplication ​

Processed webhook events are cached for 48 hours using the event ID as key. Duplicate events are silently acknowledged with 200 OK to prevent double-processing (e.g., double refunds or duplicate order confirmations).

SSRF Protection ​

Custom webhook endpoint URLs (admin-configured) are validated against private/internal IP ranges:

  • 127.0.0.1, ::1, 0.0.0.0, localhost are blocked
  • Private ranges (10.x, 172.16-31.x, 192.168.x) are blocked
  • Link-local (169.254.x) is blocked
  • DNS resolution is verified before accepting the URL

Data Protection ​

API Logger Sanitization ​

The ApiLogger middleware logs all API requests but sanitizes sensitive fields before storage: password, password_confirmation, current_password, card_number, cvv, stripe_token, payment_method_id, secret, token, api_key, webhook_secret, authorization

Model-Level Safeguards ​

  • All models use ValidatesOnSave trait — data is validated even when modified programmatically
  • Sensitive fields hidden from JSON serialization via $hidden: passwords, tokens, Stripe IDs, IP addresses, cost prices
  • Stripe client_secret only exposed when payment status is pending

Financial Safeguards ​

  • Refund validation: Amount must be > 0 and <= original payment amount
  • Wallet locking: Both credit() and debit() use SELECT ... FOR UPDATE pessimistic locks
  • Inventory protection: deduct() throws InsufficientStockException if stock would go negative
  • Payment idempotency: Each Stripe PaymentIntent uses a unique idempotency key
  • Webhook deduplication: 48-hour cache prevents double-processing of payment events

Licensed for single or extended use.