So I'm trying to write some unit/feature tests for an implementation of Passport on Lumen for our new authentication server. However I'm running into so many annoying issues I'm not even sure I'm going about doing this the right way.
The way passport is currently set up in Lumen, for web requests especially, we fake internal requests to Passport and store the client id and secret in an env file on the backend. (The client secret is hardcoded in .env so it will always be created with the same ID and secret via seeder on each dev machine) Here is the code for that:
class PassportOauth
{
const OAUTH_LOGIN = '/api/v1/oauth/token';
/**
* Functions to encapsulate the token request (login) needs
* */
public static function login($username, $password)
{
return self::clientLogin($username, $password, env('CLIENT_ID'), env('CLIENT_SECRET'));
}
public static function clientLogin($username, $password, $clientID, $clientSecret)
{
return self::post(self::OAUTH_LOGIN, [
'grant_type' => 'password',
'client_id' => $clientID,
'client_secret' => $clientSecret,
'username' => $username,
'password' => $password
]);
}
private static function post($url, $data)
{
return app()->handle(Request::create($url, 'POST', $data));
}
}
Anyways, this class works great in our dev environment. It handles requests and hands out a access token / refresh token like it's supposed to.
However, when I run unit tests testing out this class, I keep getting the error "grant type not supported," despite the password client existing in the unit test db and all the environment variables being present.
Thus, I have switched to instead of testing out the PassportOauth class, to using $this->call()
in unit tests for faking calls to Passport:
private function doLogin($email, $password)
{
return json_decode($this->call('POST', self::OAUTH_LOGIN, [
'grant_type' => 'password',
'client_id' => env('CLIENT_ID'),
'client_secret' => env('CLIENT_SECRET'),
'username' => $email,
'password' => $password
])->getContent());
}
this works great on development! Unit tests pass and everything. However, when they run in our ci/cd pipeline and it runs unit tests, I get the error that the oauth public/private keys are not installed. This is pretty obvious, I just need to run passport:install
right?
Problem is, the passport db tables aren't created in the pipeline at that moment. And I'm not sure I want to add creating the db migrations each time a ci/cd pipeline is run.
So my questions here are:
1) Am I even approaching this the right way? If I am, how do I get around the oauth private/public keys that I don't even need, because I've statically created the password client from hardcoded values in my env file?
2) Is there a better approach to unit testing this? So far my approach has given me a lot of grief.
yes, the way to test this is by not trying to unit test it. What you want is integration testing.
You would call the authentication server directly, like a normal client, you'd get a token then you start doing the other tests, what happens when the token is fine, what happens when it expires, what happens when you have the wrong token for your resource server etc.