JoaoPedro's avatar

Monolith api authentication

I have a monolith with web and API routes where the logged-in user accesses a page that makes requests to an API within the system itself. I'm having some questions about how to handle authentication for the API route. What's the best way to handle this?

I put the auth sanctum middleware around the route, but I'm always getting "unauthenticated"

Thats the ajax request i"m doing for it

$(function () { $("#download-form button").on("click", function (e) { e.preventDefault();

    let url = $("#download-form input[type='url']").val();

    if(!url || !url.startsWith("http")) {
        alert("Por favor, insira uma URL válida.");
        return;
    }

    $.ajax({
        url: "/api/download/media",
        method: "POST",
        data: {
            url: url,
            _token: $("meta[name='csrf-token']").attr("content")
        },
        success: function (response) {
            console.log(response.message);
            alert("URL salva com sucesso!");
        },
        error: function (xhr) {
            console.error(xhr.responseText);
            alert("Erro ao salvar a URL.");
        }
    });
});

});

1 like
4 replies
LaryAI's avatar
Level 58

Certainly! This is a common scenario when building a Laravel monolith where your web and API routes share authentication. Here’s what’s happening and how to solve it:

Why "Unauthenticated" Happens

When you use the auth:sanctum middleware on your API routes, Laravel expects the request to be authenticated either via:

  1. API tokens (for SPA/mobile/external clients), or
  2. Session cookies (for first-party web apps, like your case).

However, AJAX requests to /api/* routes do not automatically send the session cookie due to how browsers handle cookies and CORS, especially if your api.php routes file is used (which by default is stateless).

Solution

1. Use web Middleware for API Routes (if only accessed by logged-in users)

If your API is only used by your own frontend (not external clients), you can group your API routes with the web middleware in addition to or instead of auth:sanctum:

// routes/web.php or routes/api.php
Route::middleware(['web', 'auth'])->post('/api/download/media', [DownloadController::class, 'media']);

Or, if you want to keep it in api.php, add the web middleware:

Route::middleware(['web', 'auth'])->group(function () {
    Route::post('/download/media', [DownloadController::class, 'media']);
});

2. Make Sure AJAX Requests Send Cookies

When making AJAX requests, you must set xhrFields: { withCredentials: true } in jQuery:

$.ajax({
    url: "/api/download/media",
    method: "POST",
    data: {
        url: url,
        _token: $("meta[name='csrf-token']").attr("content")
    },
    xhrFields: {
        withCredentials: true
    },
    success: function (response) {
        console.log(response.message);
        alert("URL salva com sucesso!");
    },
    error: function (xhr) {
        console.error(xhr.responseText);
        alert("Erro ao salvar a URL.");
    }
});

3. CSRF Protection

If your API route uses the web middleware, CSRF protection is enabled. Make sure you’re sending the CSRF token (which you are).

4. Sanctum Configuration

If you want to stick with auth:sanctum, ensure you’ve configured Sanctum for SPA authentication:

  • Your frontend and backend must share the same top-level domain (or configure SANCTUM_STATEFUL_DOMAINS in .env).
  • The session cookie must be sent with the request (see step 2).

5. Summary

  • Use web middleware for internal API routes.
  • Ensure AJAX requests send cookies (withCredentials: true).
  • Use CSRF tokens as you are.
  • If using Sanctum, configure SANCTUM_STATEFUL_DOMAINS.

Example Route (web.php):

Route::middleware(['web', 'auth'])->post('/api/download/media', [DownloadController::class, 'media']);

Example AJAX:

$.ajax({
    url: "/api/download/media",
    method: "POST",
    data: {
        url: url,
        _token: $("meta[name='csrf-token']").attr("content")
    },
    xhrFields: {
        withCredentials: true
    },
    success: function (response) {
        // ...
    },
    error: function (xhr) {
        // ...
    }
});

Let me know if you need more details on any step!

Please or to participate in this conversation.