Search code examples
phplaravelvue.jssecurityserver

Security in laravel project - API interconnection


I have a new project that contains two separate parts for backend and frontend, and based on it, I want to establish a secure connection through the frontend subproject (designed with vuejs 3) with the server side API code (designed with Laravel 10). Can anyone give me a suggestion that I can establish a secure connection between the frontend sub-project and the API sub-project in such a way that it has the following conditions.

1- No one can extract data by copying codes and illegal access to API
2- The API server should be hidden from users as much as possible.

Explanation: I am thinking of a proxy server or secure proxy channel.

More Explain: I have an api that services to different client app. like telegram messenger app! so i want to service to the specify web apps and block the illegal apps to use my api.


Solution

  • You can use laravel sanctum to implement personal access tokens (PAT) to authenticate the API requests, thus preventing unauthenticated users from accessing your API endpoint, alongside with CSRF tokens that can prevent sending requests from a different origin.

    By sending a GET request to /your-domain/sanctum/csrf-cookie, an XSRF-TOKEN cookie sent from sanctum will be attached automatically to your browser, that you have to include in the "X-XSRF-TOKEN" header of every subsequent request sent from your frontend.

    On top of that, when you login you need to create an auth token for the user if the credentials are correct, this token should be sent back in the response, and stored in the client browser (in the local storage for instance), and should be included in the Authorization header of future requests, here's how it could be implemented:

    In you laravel AuthController:

    public function login(Request $request): JsonResponse
        {
    
            // Validate user input
            $request->validate([
                'login' => 'required',
                'password' => 'required|min:8'
            ]);
    
                
    
            // Attempt user authentication
            $user = $this->authService->authenticateUser($request->login, $request->password);
    
                
    
            // Check if existing tokens exist and delete them (optional)
            if ($user->tokens()) {
                $user->tokens()->delete();
            }
    
                
            // Create a new token for the user
            $token = $user->createToken('auth-token')->plainTextToken;
    
            return response()->json([
                'user' => $user,
                'authToken' => $token,
                'message' => 'Connected successfully!'
            ]);
            
        }
    

    On the client side (using axios):

    import axios from 'axios';
    
    axios.defaults.withCredentials = true;
    axios.defaults.withXSRFToken = true;
    
    const api = axios.create({
        baseURL: `${process.env.REACT_APP_API_BASE_URL}/api`,
        withCredentials: true, // This ensures that cookies are sent with cross-origin requests.
    });
    
    api.interceptors.request.use(async (config) => {
    
        const authToken = localStorage.getItem('authToken');
        if (authToken) {
            config.headers.Authorization = `Bearer ${authToken}`;
        }
    
        const csrfToken = getCookie('XSRF-TOKEN');
    
        if (csrfToken) {
            config.headers['X-XSRF-TOKEN'] = csrfToken;
        }
    
        return config;
    });
    
    const getCookie = (name) => {
        const value = `; ${document.cookie}`;
        const parts = value.split(`; ${name}=`);
        if (parts.length === 2) {
            return parts.pop().split(';').shift();
        }
        return null;
    }
    
    
    export default api;
    
    

    I use a request interceptor to include the csrf and auth token in the header of every request intercepted.

    After that you will be able to use the laravel sanctum middleware in your routes to block unauthenticated requests like this:

    Route::middleware('auth:sanctum')->group(function () {
        Route::get('/getAuth', [AuthController::class, 'getAuth']);
        Route::post('/logout', [AuthController::class, 'logout']);
    });
    

    NB: Don't forget to configure the config/cors.php to allow requests from your frontend:

    <?php
    
    return [
    
        'paths' => ['api/*', 'sanctum/csrf-cookie'],
    
        'allowed_methods' => ['*'],
    
        'allowed_origins' => ['http://localhost:3000'],
    
        'allowed_origins_patterns' => [],
    
        'allowed_headers' => ['*'],
    
        'exposed_headers' => false,
    
        'max_age' => false,
    
        'supports_credentials' => true,
    
    ];
    

    So, in summary, the attacker may be able to send a /sanctum/csrf-cookie API request from a different domain and have it processed, but they would likely be blocked by the browser from reading the response containing the CSRF token due to the Same-Origin Policy.

    Here's the documentation of sanctum for full details: https://laravel.com/docs/10.x/sanctum

    Hope it will help!