> */ protected $dontReport = [ // ]; /** * A list of the inputs that are never flashed for validation exceptions. * * @var array */ protected $dontFlash = [ 'current_password', 'password', 'password_confirmation', ]; /** * Register the exception handling callbacks for the application. * * @return void */ public function register() { $this->reportable(function (Throwable $e) { // }); } /** * Determine if the exception should use our custom rendering * even in debug mode. */ protected function shouldRenderCustom403(Throwable $e): bool { if ($e instanceof HttpException && $e->getStatusCode() === 403) { $message = $e->getMessage(); return str_contains($message, 'Unauthorized:'); } return false; } /** * Determine if exception should be reported. * We don't report ProfileAuthorizationHelper exceptions as they are expected security blocks. */ public function shouldReport(Throwable $e) { // Don't report ProfileAuthorizationHelper 403s - they're expected security blocks if ($this->shouldRenderCustom403($e)) { return false; } return parent::shouldReport($e); } /** * Prepare exception for rendering - override to prevent Whoops in debug mode * for ProfileAuthorizationHelper exceptions. */ protected function prepareException(Throwable $e): Throwable { // For our custom 403s, don't use parent preparation which might add Whoops if ($this->shouldRenderCustom403($e)) { return $e; } return parent::prepareException($e); } /** * Render an exception into an HTTP response. * * @param \Illuminate\Http\Request $request * @param \Throwable $e * @return \Symfony\Component\HttpFoundation\Response * * @throws \Throwable */ public function render($request, Throwable $e) { // Handle ProfileAuthorizationHelper 403 exceptions even in debug mode // This ensures users see friendly error pages instead of stack traces if ($this->shouldRenderCustom403($e)) { $message = $e->getMessage(); return response()->view('errors.403-profile-mismatch', [ 'exception' => $e, 'message' => $message ], 403); } return parent::render($request, $e); } }