I am designing a custom authentication scheme (based on public keys) alongside a stateless API, and decided Passport would fulfill the need for post-authentication requests.
Assuming the authentication succeeds, and the user is authenticated, they would receive a Personal Access Token, and use the token for all further requests. The trouble I'm experiencing (still after much searching through various forums and Stack Overflow) is that when using Laravel's built in testing suite, on the createToken() method, it generates an (admittedly common) exception:
"ErrorException : Trying to get property 'id' of non-object".
I am able to manually create a user through Tinker, and create a token through Tinker. However I'm experiencing problems when attempting to automate this process after authenticating.
Here is the relevant code snippet post-authentication:
Auth::login($user);
$user = Auth::user();
$tokenResult = $user->createToken('Personal Access Token');
$token = $tokenResult->token;
$token->expires_at = Carbon::now()->addWeeks(1);
$token->save();
return response()->json([
"access_token" => $tokenResult->accessToken,
"token_type" => "Bearer",
"expires_at" => Carbon::parse(
$tokenResult->token->expires_at)->toDateTimeString()
],
200);
I've manually called Auth::login on the user, to ensure the user is logged in, and Auth::user() returns the user (not null). Upon executing the third line of code, the exception is thrown with the following mini stack-trace (I can provide a full stack-trace if requested).
laravel\passport\src\PersonalAccessTokenFactory.php:100
laravel\passport\src\PersonalAccessTokenFactory.php:71
laravel\passport\src\HasApiTokens.php:67
app\Http\Controllers\Auth\LoginController.php:97
laravel\framework\src\Illuminate\Routing\Controller.php:54
laravel\framework\src\Illuminate\Routing\ControllerDispatcher.php:45
From running this through debug a few times- even though the class is called and loaded, and it appears the Client is found through ControllerDispatcher -> Client::find(id) and found in ClientRepository, when it gets to PersonalAccessTokenFactory, the $client passed in is null (which explains why the $client->id can't be found, though I have no idea why the $client is null at this point).
protected function createRequest($client, $userId, array $scopes)
{
$secret = Passport::$hashesClientSecrets ? Passport::$personalAccessClientSecret : $client->secret;
return (new ServerRequest)->withParsedBody([
'grant_type' => 'personal_access',
'client_id' => $client->id,
...
}
Things I have done/tried with some guidance from the documentation and other posts:
- Manually created a user in Tinker, and created the token through Tinker- this does work.
- Ensured the user is logged in before attempting to generate token.
- passport:install (and adding the --force option)
- Ensured Personal Access Client is generated with passport:client --personal
- Ensured the AuthServiceProvider::boot() contains the ClientID and Client Secret (in the .env).
- migrate:refresh followed by passport:install --force
- Complete removal of Passport, removing all files, keys, migrations, and DB entries, followed with a migrate:refresh and reinstallation of Passport, along with generating an additional personal access client (even though one is generated during passport:install).
I'm not sure where else to look/what else to try at this point, so any help or guidance would be much appreciated!