oliverbj
oliverbj

Reputation: 6052

Securing internal API endpoint with Laravel

I have a web application where users can upload documents.

A user can upload many documents (hasMany).

I have below Vue file, that fetches my internal API to get the information from an uploaded document. Below is the method I am using:

ShowDocument.Vue

getDocument: function (documentId) {
    axios.get('/api/documents/' + documentId).then((response) => {
        this.document = response.data.document;
    }).catch(error => {
        console.log(error);
    })

},

In my routes/api.php file, I have defined below route:

Route::apiResource('documents', 'Api\DocumentsController')->middleware('ajax')->only(['show']);

As you can see, I have a custom middleware called ajax. This makes sure that only AJAX requests to the API endpoint are accepted:

app\Http\Middleware\RequestIsAjax.php

public function handle($request, Closure $next)
{
    if (! $request->ajax())
        return abort(403);
    return $next($request);
}

Further, the DocumentsController simply looks like this:

public function show($id)
{
    $document = Document::findOrFail($id);

    return response()->json([
        'document' => $document,
    ], 200);
}

So far so good. Now, my problem is - this API endpoint is only used internally (for now), but as a user I can easily view the information of another users document, by simply sending an AJAX request to:

/api/documents/<documentID>

and simply replace with another number.

My question is, how can I prevent this and ensure that only the user can view their own documents?

Upvotes: 0

Views: 653

Answers (1)

Kenny Horna
Kenny Horna

Reputation: 14241

You could add an additional check. It could be as rudimentary as this:

public function show($id)
{
    $document = Document::findOrFail($id);

    if ($document->user_id !== auth()->id())
    {
        return response()->json([
            'message' => 'You are not allowed to see this document',
        ], 403);
    }

    return response()->json([
        'document' => $document,
    ], 200);
}

Alternatively, you could also do this when finding the document (because it seems you are not using Model Binding), so this should also work:

public function show($id)
{
    $document = Document::where('user_id', auth()->id)->find($id);

    if ($document)
    {
        return response()->json([
            'message' => "The document does not exist or you are not allowed to see it.",
        ], 404);
    }

    return response()->json([
        'document' => $document,
    ], 200);
}

Then again, you could implement this in not only in the controller but in a middleware, a Form Request, and so on.

Upvotes: 1

Related Questions