Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

SamSha's avatar
Level 1

React SPA + Laravel API

Subject: Help Needed with Image Display Issue in React and Laravel (Sanctum Authentication)

Hi everyone, I'm reaching out for help with an issue that I’ve been struggling with for a few days. I’ve tried various solutions, but nothing seems to work.

The Situation:

• Frontend: I’m using React (version 8.2.0) as a single-page application (SPA). • Backend: I have a Laravel API (version 11.30.0) for authentication, and I’m using Sanctum for SPA cookie-based authentication (not token-based, so no Bearer token).

On my local machine, everything works fine. However, when I deploy to production, I face an issue where the image doesn’t display in React when I use a middleware for the route. When the middleware is removed, the image displays fine, and there is no issue.

The Setup:

• Image Location: The images are stored in storage/app/private/{userId}/image.webp (where {userId} is dynamic). • I haven’t created a symlink between storage/app/private and the public folder because I don’t want users to access the images directly. The goal is to make the images accessible only within the app.

The Problem:

• When I try to display the image in React, I get the following error in the browser’s developer console: (failed) net::ERR_BLOCKED_BY_ORB • If I remove the middleware from the route, the image displays without any issues. But with the middleware in place, it’s blocked.

What I’ve Considered:

• I know one potential solution is to make an HTTP request to retrieve the image and then use the returned URL in the src of the tag. However, this adds extra HTTP requests to the server, and I’m not keen on that approach.

What I Need:

• Can someone please help me figure out how to fix this issue without adding unnecessary HTTP requests? I really appreciate any suggestions or advice.

Thank you so much for your time and help!

File: httpService.jsx This is the configuration for Axios, which includes settings for sending requests with credentials and CSRF tokens.

import axios from "axios";

axios.defaults.withCredentials = true;
axios.defaults.withXSRFToken = true;
const baseURL = (axios.defaults.baseURL = import.meta.env.VITE_API_URL);
const http = {
  get: axios.get,
  post: axios.post,
  put: axios.put,
  delete: axios.delete,
  baseURL: baseURL,
};

File: Profile.jsx

This is the code for the Profile.jsx file, which imports the httpService and dynamically loads the image from the server:


import http from "../../../services/httpService";

// Note, id and mainPhoto are already returned from the server

<img
  src={`${http.baseURL}/api/private/${id}/tiny_${mainPhoto.photo_name}`}
  alt="Profile"
/>

File: api.php

This is the route definition for the api.php file, which uses middleware to protect the private image route:


Route::get("/private/{id}/{image}", [PrivateController::class, "images"])
    ->middleware("auth:sanctum");

File: PrivateController.php

This is the code for the PrivateController.php file, which handles the retrieval of private images from storage:

<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Storage;

class PrivateController extends Controller
{
    public function images($id, $image)
    {
        $path = "{$id}/{$image}";

        // Check if the image exists in private storage
        if (Storage::disk('private')->exists($path)) {
            return Storage::disk('private')->response($path);
        }

        abort(404);
    }
}

File: cors.php

This is the configuration file for cors.php, which handles Cross-Origin Resource Sharing (CORS) settings in your Laravel application:

File: .env

This is the configuration for the .env file, which defines various settings for your Laravel application:

APP_URL=https://api.example.net

SANCTUM_STATEFUL_DOMAINS=example.net

SESSION_DRIVER=cookie
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=.example.net

FILESYSTEM_DISK=private

File: filesystems.php

This is the configuration for the filesystems.php file, which defines the settings for your private storage disk:

"private" => [
    "driver" => "local",
    "root" => storage_path("app/private"),
    "visibility" => "private",
],
0 likes
0 replies

Please or to participate in this conversation.