I’m trying to do OAuth2 authorization on Laravel 10 using the API. Registration and authorization works, but I can’t get a token either during registration or authorization. It would be correct to say that I am not receiving the token in the form in which it can be used in further requests. See data.access_token
:
{
"success": true,
"data": {
"id": 1,
"name": "Schizo",
"email": "********@gmail.com",
"access_token": {
"name": "DesktopClient",
"abilities": [
"*"
],
"expires_at": null,
"tokenable_id": 1,
"tokenable_type": "App\Models\User",
"updated_at": "2023-07-08T16:22:30.000000Z",
"created_at": "2023-07-08T16:22:30.000000Z",
"id": 2
}
},
"message": "User login successfully."
}
I expect to see the token in this form:
Versions
- PHP 8.1.21
- Laravel Framework 10.14.1
- Laravel Passport 11.8.8
Some general information
Before the test, the command to create a personal access client was executed:
php artisan passport:client --personal --no-interaction
Command output:
Personal access client created successfully.
Client ID: 16
Client secret: KjpvwyB1XMZTfh8aFZzrSJZrb3di83JZsj6ZvRud
After that in the database, a row was created in the oauth_clients
table:
and in oauth_personal_access_clients
table:
Then I added the id and secret key to the .env file.
.env
PASSPORT_PERSONAL_ACCESS_CLIENT_ID=16
PASSPORT_PERSONAL_ACCESS_CLIENT_SECRET=KjpvwyB1XMZTfh8aFZzrSJZrb3di83JZsj6ZvRud
config/auth.php
return [
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
'hash' => true,
],
],
];
routes/api.php
Route::post('register', [AuthController::class, 'register']);
Route::post('login', [AuthController::class, 'login']);
app/Http/Controllers/AuthController.php
namespace AppHttpControllersApi;
use AppHttpRequestsApiLoginRequest;
use AppHttpRequestsApiRegisterRequest;
use AppHttpResourcesUserResource;
use AppModelsUser;
use IlluminateHttpJsonResponse;
use IlluminateSupportFacadesAuth;
class AuthController extends ApiController
{
/**
* Performs user registration.
*
* @param ApiRegisterRequest $apiRegisterRequest
* @return JsonResponse
*/
public function register(ApiRegisterRequest $apiRegisterRequest): JsonResponse
{
$input = $apiRegisterRequest->validated();
$input['password'] = bcrypt($input['password']);
return $this->sendResponse(
$this->getUserResourceWithAccessToken(User::create($input)),
'User register successfully.'
);
}
/**
* Performs user authorization.
*
* @param ApiLoginRequest $apiLoginRequest
* @return JsonResponse
*/
public function login(ApiLoginRequest $apiLoginRequest): JsonResponse
{
if (!Auth::attempt($apiLoginRequest->validated())) {
return $this->sendError('Unauthorised.', [
'error' => 'Unauthorised.'
]);
} else {
return $this->sendResponse(
$this->getUserResourceWithAccessToken(Auth::user()),
'User login successfully.'
);
}
}
/**
* Returns compressed user data with an access token.
*
* @param User $user
* @return UserResource
*/
private function getUserResourceWithAccessToken(User $user): UserResource
{
return new UserResource(array_merge($user->getAttributes(), [
'access_token' => $user->createToken('X-Soft Personal Access Client')->accessToken,
]));
}
}
app/Http/Controllers/ApiController.php
namespace AppHttpControllersApi;
use AppHttpControllersController;
use IlluminateHttpJsonResponse;
class ApiController extends Controller
{
/**
* Success response method.
*
* @param mixed $result
* @param string $message
* @return JsonResponse
*/
public function sendResponse(mixed $result, string $message): JsonResponse
{
return response()->json([
'success' => true,
'data' => $result,
'message' => $message,
]);
}
/**
* Return error response.
*
* @param string $error
* @param array $errorMessages
* @param int $code
* @return JsonResponse
*/
public function sendError(string $error, array $errorMessages = [], int $code = 404): JsonResponse
{
$response = [
'success' => false,
'message' => $error,
];
if (!empty($errorMessages)) {
$response['data'] = $errorMessages;
}
return response()->json($response, $code);
}
}
I was advised to add the api_token
field in the users table, since in the file config/auth.php the guards.api.provider
parameter specifies users
. However, this did not help solve the problem, which is obvious. I tried to completely repeat the algorithm of actions described in this article.
2
Answers
please check your User Models,
user model should have HasApiTokens
First check in your User model namespace should like this if you need direct token
Not
If you need a robust OAuth2 implementation with features like authorization codes, token refreshing, and third-party application integration, go for Passport (
use LaravelPassportHasApiTokens
).If your application is relatively simple and you want quick, stateless API authentication, especially for SPAs and mobile apps, Sanctum (
use LaravelSanctumHasApiTokens
) might be the better choice. And it can be access by