laravel / framework

The Laravel Framework.
https://laravel.com
MIT License
32.54k stars 11.02k forks source link

laravel test "remembers" api_token authentication for unauthenticated followup request #38161

Closed grasmanek94 closed 3 years ago

grasmanek94 commented 3 years ago

Description:

Using sanctum middleware. Laravel test requests seem to remember some kind of additional authentication, on top of the provided token. There's nothing to clear the cookies. Flushing the headers does not work either. Resetting the value of the authorization header doesn't work either.

Steps To Reproduce:

Running test cases that logically authenticate a request, and then perform an unauthenticated request, reproduces this. Example:

<?php

namespace Tests\Feature\Web\Api;

use App\Models\Device;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class DevicesApiTest extends TestCase
{
    use RefreshDatabase;

    private string $token;

    public function setUp(): void
    {
        parent::setUp();

        $this->seed();

        $user = User::factory()->create();
        $this->token = $user->createToken('token')->plainTextToken;
    }

    private function auth()
    {
        return $this->withToken($this->token);
    }

    private function guest()
    {
        return $this->withToken('','');
    }

    public function test_device_list_no_authentication() // PASS
    {
        $this
            ->guest()
            ->getJson(route('api.device'))
            ->assertJson(['message' => 'Unauthenticated.'])
            ->assertStatus(401);
    }

    public function test_device_list_authentication() // PASS
    {
        $this
            ->auth()
            ->getJson(route('api.device'))
            ->assertSuccessful()
            ->assertStatus(200);
    }

    public function test_device_list_combined_authentication_pass() // PASS
    {
        $this
            ->guest()
            ->getJson(route('api.device'))
            ->assertJson(['message' => 'Unauthenticated.'])
            ->assertStatus(401);

        $this
            ->auth()
            ->getJson(route('api.device'))
            ->assertSuccessful()
            ->assertStatus(200);
    }

    public function test_device_list_combined_authentication_fail() // FAIL
    {
        $this
            ->auth()
            ->getJson(route('api.device'))
            ->assertSuccessful()

        $this
            ->guest()
            ->getJson(route('api.device'))
            ->assertJson(['message' => 'Unauthenticated.'])
            ->assertStatus(401);

    }
}

Extra:

Same issue as https://github.com/laravel/framework/issues/30677

I don't understand how this is expected behaviour?
Can I know the rationale behind this if this is not a bug?

driesvints commented 3 years ago

Hi there,

Thanks for reporting but it looks like this is a question which can be asked on a support channel. Please only use this issue tracker for reporting bugs with the library itself. If you have a question on how to use functionality provided by this repo you can try one of the following channels:

However, this issue will not be locked and everyone is still free to discuss solutions to your problem!

Thanks.

grasmanek94 commented 3 years ago

@driesvints the file https://github.com/laravel/framework/blob/v8.49.2/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php belongs to the laravel/framework repository.

The functions in this class prepare and perform the requests, as far as I'm aware. It hides away any access to low level HTTP stuff, which means I cannot, without reflection/breaking encapsulation, fix this in my tests (and guarantee the code will work in the future).

How is this not a bug? (result differs from expected behaviour).