Reputation: 2405
I've created a Laravel backend with an API. In addition, I added Laravel passport for authentication.
Right now I want to access the API with my ReactJS Frontend application and with a React-Native application. The ReactJS application is on the same server as the Laravel backend.
Now I'm looking for the best way to connect everything with the best security.
I've been looking around and checking tutorials, HowTos, ... for over a week now and I don't know what is best.
Right now my "setup" is, because of some threads and stuff, like this:
I checked the Laravel documentation and several HowTos and implemented the Password Grant Client
in my application:
public function login(Request $request){
$http = new GuzzleHttp\Client;
$response = $http->post(env('APP_URL') . '/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => env('PASSWORD_CLIENT_ID'),
'client_secret' => env('PASSWORD_CLIENT_SECRET'),
'username' => $request->input('email'),
'password' => $request->input('password'),
'scope' => '',
],
]);
$responseJSON = json_decode($response->getBody(), true);
$output = array(
'access_token' => $responseJSON['access_token'],
'expires_in' => $responseJSON['expires_in']
);
return response($output)
->header('Content-Type', 'application/json')
->cookie('refreshToken', $responseJSON['refresh_token'], 14400, null, null, true, true);
}
and for refreshing the token:
public function tryRefresh(Request $request) {
$http = new GuzzleHttp\Client;
$refreshToken = $request->cookie('refreshToken');
$response = $http->post(env('APP_URL') . '/oauth/token', [
'form_params' => [
'grant_type' => 'refresh_token',
'refresh_token' => $refreshToken,
'client_id' => env('PASSWORD_CLIENT_ID'),
'client_secret' => env('PASSWORD_CLIENT_SECRET'),
'scope' => '',
],
]);
$responseJSON = json_decode($response->getBody(), true);
$output = array(
'access_token' => $responseJSON['access_token'],
'expires_in' => $responseJSON['expires_in']
);
return response($output)
->header('Content-Type', 'application/json')
->cookie('refreshToken', $responseJSON['refresh_token'], 14400, null, null, true, true);
}
Access Token is set to 30 min and refresh token to 10 days. Everything works but I don't know if this is a good practice because:
So my question is: What is a good/best practice for my kind of use case, so the authentication is secure and working on both (ReactJs Web-App and React-Native Mobile App).
Upvotes: 1
Views: 2948
Reputation: 1127
The idea is to do as follows:
secure
option, not the httpOnly
one (this will never pass the cookie value to the client)Authorization
header to the backend from your client, i'm using axios, so it is as simple as request.headers.common['Authorization'] = `Bearer ${token}`;
Here are the examples of my log in and log out methods:
/**
* Authenticate user.
*
* @param Request $request
*
* @return JsonResponse
*/
public function authenticate(Request $request): JsonResponse
{
$validator = Validator::make($request->all(), [
'email' => 'required|string|email',
'password' => 'required|string|min:8',
'remember_me' => 'boolean',
]);
if ($validator->fails()) {
return $this->sendError('errors.invalid_request', $validator->errors()->toArray(), Response::HTTP_BAD_REQUEST);
}
$credentials = request(['email', 'password']);
if (!\Auth::attempt($credentials)) {
return $this->sendError('errors.account.invalid_credentials', [], Response::HTTP_FORBIDDEN);
}
$user = $request->user();
if (!$user->active) {
return $this->sendError('errors.account.inactive', [], Response::HTTP_CONFLICT);
} elseif (null !== $user->deleted_at) {
return $this->sendError('errors.account.deleted', [], Response::HTTP_CONFLICT);
}
$createdToken = $user->createToken(sprintf('Access token for %s', $user->username));
$token = $createdToken->token;
if ($request->remember_me) {
$token->expires_at = now()->addYears(1);
}
$token->save();
return $this->sendResponse('account.status.authenticated', [
'access_token' => $createdToken->accessToken,
'token_type' => 'Bearer',
'expires_at' => Carbon::parse($createdToken->token->expires_at)->toDateTimeString(),
]);
}
/**
* Logout user and revoke access token.
*
* @param Request $request
*
* @return JsonResponse
*/
public function logout(Request $request): JsonResponse
{
$request->user()->token()->revoke();
return $this->sendResponse('account.status.logged_out');
}
Upvotes: 0
Reputation: 5452
Given the frameworks you want to use, the token based authentication you have implemented IS good practice.
You can also look into JWT as an alternative to Password Grant type authentication.
Upvotes: 1