How to make a Component accessible for authenticed users only?

What seems to be the problem: I’m trying to make a component available only for authenticated users.

Steps to Reproduce:

▶ php artisan livewire:make AuthTest
 COMPONENT CREATED  🤙

CLASS: app/Http/Livewire/AuthTest.php
VIEW:  resources/views/livewire/auth-test.blade.php

Livewire Component:

namespace App\Http\Livewire;

use Illuminate\Support\Facades\Auth;
use Livewire\Component;

class AuthTest extends Component
{
    public $message;

    public function thisShouldBeOnlyPossibleIfYourAuthenticated() {
        // do some stuff for logged in users only
        // guest should not be able to enter this function
        // or better guest should not be able to interact with this component
        
        $this->message = "User authenticated: " . Auth::check()?'true':'false';
    }

    public function render()
    {
        return view('livewire.auth-test');
    }
}

Template:

<div>
    {{-- @auth only hide this code from unauthenticated users--}}
    @auth() 
    {{ $message }}
    <button wire:click="thisShouldBeOnlyPossibleIfYourAuthenticated">submit</button>
    @endauth
</div>

What happens:
If you click on the submit button, the following request will be sent:

curl 'https://sample.home/livewire/message/auth-test' \
  -H 'authority: sap.home' \
  -H 'pragma: no-cache' \
  -H 'cache-control: no-cache' \
  -H 'sec-ch-ua: "Google Chrome";v="89", "Chromium";v="89", ";Not A Brand";v="99"' \
  -H 'x-csrf-token: uXDoq2rNtIN1NVOW28zmwJ3xwDei1MvfBwVuvO4A' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36' \
  -H 'x-livewire: true' \
  -H 'content-type: application/json' \
  -H 'x-socket-id: undefined' \
  -H 'accept: text/html, application/xhtml+xml' \
  -H 'origin: https://sap.home' \
  -H 'sec-fetch-site: same-origin' \
  -H 'sec-fetch-mode: cors' \
  -H 'sec-fetch-dest: empty' \
  -H 'referer: https://sample.home/' \
  -H 'accept-language: de-DE,de;q=0.9,en;q=0.8,fr;q=0.7,da;q=0.6' \
  -H 'cookie: XSRF-TOKEN=eyJpdiI6IkxLUnVUZ1hhbHQwUWRBWjhGbjJjTlE9PSIsInZhbHVlIjoiaE5qT2RoajF3bHFuSzR0Z0srMXdUaE5NUkZ1SkM5N2ZNbjdSU2hKQVI0bDVvWGFBMG1PRlJkN2k5YTdBMit2TnhYQnJMWUwrbVJsWHVKRHRBakoxNHBKaWY0dGRqd3p5bDVhUm9wS0dXenJuamV3cGRmbURtQzdHaGFDOFlVdzEiLCJtYWMiOiIwYjRlODIxZmQyZjYxOGZmMDMyNGMwOWRkNmM5ZWM3MjQ3YjQ0NzBhMGVmOTFhYzY2ODFjYThjYzcxZmNjMTNlIn0%3D; blubb_session=eyJpdiI6Imx3WHlaVFVEclJHbWFDZVB5d2RvcVE9PSIsInZhbHVlIjoibDQxZVZkTDUxczhTbVhGUkZhMlFrZWdIUUlRejlwVDRDSUNxSXJwNVpYZXlQeTNqcWlmRGIrdjBXWndUSXp6bHA2SGNjYWRyS1F1Zlp0OUZHWTNDUFNHNU5NMWhHU0w4WVk1Yll4N2VMVU5vMUtKUFd4KzZkdXRpWnlvN0k3LzYiLCJtYWMiOiI1N2M5ZjEyZjQ2MjQ4ZjU5ODFjMmFkNzFjOGUzOWU2MTdlYzU2ODg5OTlhMjAwNjdiZTVkNTc1NTYxNThlYTY0In0%3D' \
  --data-raw '{"fingerprint":{"id":"e8sVcYc18eo7WjmfDMyf","name":"auth-test","locale":"en","path":"/","method":"GET"},"serverMemo":{"children":[],"errors":[],"htmlHash":"a1b62bf6","data":{"message":"true"},"dataMeta":[],"checksum":"62784730641e3a2d0aa64a971e7a3426a1e13183727b6021c459eb578d4128e1"},"updates":[{"type":"callMethod","payload":{"method":"thisShouldBeOnlyPossibleIfYourAuthenticated","params":[]}}]}' \
  --compressed

Are you using the latest version of Livewire: I’m using versions v2.4.1

How can I make this component only accessible for authenticated users, including every callable method. Maybe there is a solution similar to

Route::middleware(['auth'])->post('/livewire/message/auth-test', '...');

to make sure only authenticated users can pass.

cheers,

J

The fact that the button is rendered and you can click it would indicate that you’re an authenticated user. Are you wanting to do a second check when the function gets called?

Hej @Pom ,

Interestingly, everyone who knows the route can send a request to /livewire/message/auth-test.

The button is rendered based on blade helper function @auth, but it isn’t a real check. Keep your eyes focused on the wire:click method and the corresponding curl request.

My question is, how can I make this route as safe as possible.

Sure, i can implement something like this:

public function mount() {
    Auth::check()?:abort(403);
}

but it isn’t the same. IMHO it should redirect to /login route and then back

J

Just add the ‘auth’ middleware to your route. Livewire will capture the middleware and use it for any further requests.

Route::get('/auth-test', AuthTest::class)->middleware('auth');

Hej again,

as far as I know, the given route
/livewire/message/auth-test
is based on

▶ php artisan route:list -c | grep -i livewire/message
| POST | livewire/message/{name} | Livewire\Controllers\HttpConnectionHandler  |

IMHO, I can overwrite this route and add some middleware configurations. But something telling me, that this is not the recommended way to do this.

cheers,

J

If you send a POST request to /livewire/message/auth-test from outside of the component all you’re going to get in response is a 419 Page Expired.

You can also write Gates, policies, etc. Laravel documentation refers to different ways for authorization.
https://laravel.com/docs/8.x/authorization