degeta10's avatar

OAuth token not generating in test environment

  • Passport Version: 10.2
  • Laravel Version: 8.77.1
  • PHP Version: 7.3.33
  • Database Driver & Version: MySQL v8.0.27

Description:

I had created an API for login using passport. It authenticates using "/oauth/token" URL with password grant type. The API works in the application as well as postman. But while calling the API in tests, it says "Client authentication failed". I've made sure the database migration and passport:install commands are called before calling the API in the test function. But still doesn't work. I tried many solutions like calling a proxy request but the error still remains. Please help. Below is my code for the API:

    public function login(LoginRequest $request)
    {
        if (Auth::attempt($request->validated())) {
            $oClient = PassportClient::where('password_client', 1)->first();
            return $this->getTokenAndRefreshToken($oClient, request('email'), request('password'));
        } else {
            return new JsonResponse(
                ['message' => 'Invalid credentials'],
                Response::HTTP_UNAUTHORIZED
            );
        }
    }

    public function getTokenAndRefreshToken(PassportClient $oClient, $email, $password)
    {
        $response = Http::asForm()->post(config('app.url') . '/oauth/token', [
            'grant_type'    => 'password',
            'client_id'     => $oClient->id,
            'client_secret' => $oClient->secret,
            'username'      => $email,
            'password'      => $password,
            'scope'         => '*',
        ]);

        if ($response->successful()) {
            return new LoginResource($response->json());
        } else {
            return new JsonResponse(
                ['message' => 'Authentication failed'],
                Response::HTTP_UNAUTHORIZED
            );
        }
    }

Below is my test class:

    use RefreshDatabase;

    protected function setUp(): void
    {
        parent::setUp();
        // $this->artisan('migrate:fresh');
        // $this->artisan('passport:install', ['-vvv' => 1]);
        $this->artisan('passport:install');
    }

    public function test_user_can_login_using_api()
    {
        $this->withoutExceptionHandling();
        $user = \App\Models\User::factory()->create();
        $this->postJson(
            '/api/auth/login',
            [
                'email'     => $user->email,
                'password'  => 'password'
            ],
            ['Accept' => 'application/json']
        )->assertStatus(200);
    }

Steps To Reproduce:

This is my repository where It can be tested.

0 likes
4 replies
mabdullahsari's avatar

Use Sanctum.

OAuth is not meant to be used to authenticate your own apps.

degeta10's avatar

@mabdullahsari Yea but, I wanted to use passport so I can implement refresh token mechanism. Let me know what I can do the solve this issue using passport itself. The only way I can make it work is by changing the env variable DB_DATABASE to that of testing database's name, clearing cache and then running the test. I don't know why it works in that case. Also I don't even know if this has to be considered as a bug or configuration issue.

mabdullahsari's avatar

@degeta10 Sanctum also provides a refresh mechanism..? I don't understand how a technical detail can take part in your decision making. You want to use Passport because it can refresh tokens, there is no business need behind it? OK.

1 like
degeta10's avatar

@mabdullahsari Okay, I didn't know that refresh token mechanism was there in sanctum too. I didn't really think of searching it even. My bad. The reason I'm using passport is just that I've seen the passport package providing refresh tokens. Thanks for letting me know about this :)

Please or to participate in this conversation.