2

I am trying to create a Feature test that tests getting an OAuth access token. When using Postman, everything works great (actual code) so I am confident it is in my test code I am not implementing the setup correctly.

In the past, I have run the artisan command, and simply copy/paste the client_secret into my .env file. Because I am using CI/CD, I cannot do that. I need to either:

  • create an artisan command to append the .env
  • read the secret from the oauth_clients table (seems the easiest route)

I've followed this SO thread to help get where I'm at, but not able to make it work.

Here is what my test looks like:

MyFeatureTest.php

use RefreshDatabase, WithFaker, DatabaseMigrations;

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

    $this->artisan('passport:install');
}


public function a_user_can_get_a_token()
{
    $credentials = [
        'username' => 'username',
        'password' => 'password',
    ];

    $http = $this->postJson('api/v1/login', $credentials);

    $response = json_decode($http->getContent());

    // dd($response);

    $http->assertStatus(200)
        ->assertJsonStructure([
                'token_type', 'expires_in', 'access_token', 'refresh_token',
            ])
            ->assertJson([
                'token_type' => $response->token_type,
                'expires_in' => $response->expires_in,
                'access_token' => $response->access_token,
                'refresh_token' => $response->refresh_token,
            ]);

In my Controller that handles the login route:

public function __construct()
{
    $this->client = DB::table('oauth_clients')
        ->where('id', 2)
        ->first();
}


...


public function getOauthAccessToken($credentials)
{
    $response = Http::asForm()->post(env('APP_URL') . '/oauth/token', [
        'grant_type' => 'password',
        'client_id' => $this->client->id,
        'client_secret' => $this->client->secret,
        'username' => $credentials['username'],
        'password' => $credentials['password'],
        'scope' => '*',
    ]);

    if ($response->successful()) {
        return $response->json();
    } else {
        dd($response->body());
    }
}

When using postman to test my routes/controller, everything works great. I get a Barer token back as expected.

When I run my Feature test, my controller returns null. Trying to troubleshoot, I've tried dd($response->body()) above. Here is what I am getting:

"{"error":"invalid_client","error_description":"Client authentication failed","message":"Client authentication failed"}"

If I dd($this->client->secret), I am able to see the key. This is super confusing as it looks like everything is working...

How can I properly set up my test so that passport is ready to go/configured when I hit the login test(s)? Thank you for any suggestions!

Damon
  • 4,151
  • 13
  • 52
  • 108

1 Answers1

2

Thank you everyone for your suggestions!

This is what ended up working for me. Since I am the only consumer of my api, I don't need to return the entire /oauth/token response (although it might be helpful in the future).

MyTest.php

 use RefreshDatabase, WithFaker, DatabaseMigrations;

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

    $this->artisan('passport:install', ['--no-interaction' => true,]);
}


/** @test */
public function a_user_can_authenticate_using_email()
{
    $credentials = [
        'username' => 'test@email.com',
        'password' => 'password',
    ];

    $http = $this->postJson('api/v1/login', $credentials)
            ->assertStatus(200);
}

MyController.php

// authenticate the $credentials to get a $user object.

...

return $this->getOauthAccessToken($user);

...

private function getOauthAccessToken($user)
{
    $token = $user->createToken('My Personal Access Token')->accessToken;

    return response()->json($token);
}

Instead of validating I get the exact json back (would be ideal) I'm just verifying that I'm getting a 200 response back. Because my authentication is somewhat cumbersome (checking multiple db's) it was important to make sure that I was getting through everything with a 200.

Hope this helps someone!

Damon
  • 4,151
  • 13
  • 52
  • 108