I have a small Lumen / Laravel app that is just used as an API. I am able to sign in and set JWT tokens but after a period of time they timeout, I was expecting them to refresh each time an Endpoint was hit.
I've been looking at the docs for Tymon's JWT-AUTH but I cannot seem to get it to work.
Below is an example of one of my end points which return an array of all the users in the db. But when the token timesout the endpoint returns the error You don't have previleges to view all users
I'd be very grateful if someone was able to advise me or show me how to make my code refresh a token when someone is hitting an endpoint.
Inside Controller
public function index(Request $request)
{
$user = JWTAuth::parseToken()->authenticate();
if (!$user->isAdmin()) {
return $this->error_respond(['error' => "You don't have previleges to view all users"]);
}
$users = $this->repository->findAllWithPlan();
return $this->respond(['users' => $users]);
}
Inside Routes.php
$app->group(['middleware' => 'jwt.auth'], function ($app) {
/**
* Show All users
*/
$app->get(
'users',
[
'as' => 'user.all',
'middleware' => 'cors',
'uses' => 'App\Http\Controllers\UserController#index'
]
);
});
Related
Hello i'm newbie in laravel. I use for authorization sanctum. But i want that some request can available for authorization user (i use laravel for only api, on front i use angular 2).
web.php:
Route::group(['middleware' => ['auth:sanctum']], function () {
Route::post('api/user-information', function(Request $request) {
return response()->json([ auth()->user()]);
});
// API route for logout user
Route::post('api/logout', [AuthController::class, 'logout']);
});
How can I get access token after success autorization user that i can send request for middleware routes. Because if i have request withous access token i always send null in 'api/user-information'. Please help me resolve this problem.
You could better make a new function in a controller, probably the AuthController. In this function you can validate fields
$validatedData = $request->validate([
'email' => ['required', 'email'],
'password' => ['required'],
]);
With the validated data you can use Auth::login($validatedData);
Source: https://laravel.com/docs/9.x/authentication#login-throttling
Welcome to Laravel! I am assuming you have login method that authenticates user. You can create a token in that method and pass it to your frontend.
public function login(Request $request)
{
$request->validate([
'email' => 'required|email',
'password' => 'required',
]);
$user = User::where('email', $request->email)->first();
if (! $user || ! Hash::check($request->password, $user->password)) {
return ['status'=>0,'message'=>'Invalid Credentials','data'=>[]];
}
$data = [
'user'=>$user,
'token'=>$user->createToken('MyToken')->plainTextToken
];
return ['status'=>1, 'message'=>'Login Successful!', 'data'=>$data];
}
If you just need to pass the token, you can simply return token in the response and then pass it in request header (Authorization) of your Angular applcation to access the API routes protected by Sanctum middleware auth:sanctum
return $user->createToken('MyToken')->plainTextToken;
Also since you are going to use Laravel for API, I would suggest you put all your routes in routes/api.php file.
The routes in routes/api.php are stateless and are assigned the api middleware group. The prefix '/api' is applied to all the routes defined in api.php
You can read more about it in Laravel Documentation
Issuing API Tokens
The Default Route Files
Is there any way that I can allow user to login only from one device?
Thanks in advance
Well, you would need to check at a central place, if there is an already existing session for the user that currently want to log in - and if yes, delete all existing sessions.
The central place would proably be when the login happens or inside an auth middleware.
To delete all existing sessions for the user you can run
DB::table('sessions')->where('user_id', $user->id)->delete();
Log in only from one device, f. ex. Laptop
That is probably not possible as each device would need to send a unique identifier - which it doesn't. As example, your Laptop would need to send a unique identifier to the Laravel system, so that your Laravel application would know, that it is the Laptop the login is coming from.
The login forms normally only takes a username/email and a password, so no unique property to identify your Laptop.
You could probably check for browser user agent or things like this, but that is all fakeable and does not guarantee a 100% proof identification of the device.
You can use deviceInspect middleware and check user agent (it could be fake as #codedge said) and use it after auth middleware
As you can see the user will be authenticated but routes will be protected by device
Create middleware
class DeviceInspect
{
public function handle($request, Closure $next)
{
$user = Auth::user(); //or $request->user()
// TODO get enabled device/s from datebase for $user - by userId
$enabledDevice = "Dalvik/2.2.0 (Linux; U; Android 10.0.1; AM-A89R Build/NMB55D)"; //example
$currentDevice = $request->userAgent(); //or $_SERVER['HTTP_USER_AGENT'];
//it could be fake like codedge said
if ($enabledDevice !== $currentDevice) {
$data = array(
"device" => false,
"message" => "your message to user",
);
return response([$data], 401); // or something else
}
return $next($request);
}
}
add this to App\Http\Kernel
protected $routeMiddleware = [
...
'device' => 'App\Http\Middleware\DeviceInspect',
];
and use it like below
//in controller
class SomeController extends Controller {
public function __construct() {
parent::__construct();
$this->middleware(['auth', "device"]);
}
}
or
//Or in routes
Route::get('/profil', function () {
//
})->middleware(['auth', 'device']);
or
Route::group(['prefix' => '/v1/data', 'namespace' => 'Api\V1', 'as' => 'api.', 'middleware' => ['auth:api', 'device']], function () {
Route::resource('activity', 'Data\DataController', ['only' => ['index', 'show']]);
});
I am developing an app where I am fetching user details with Laravel passport API get method with query string.
But when I put that route in auth API it shows "route login not found" and when I put outside auth API it shows Null when I call Auth::user().
Here is my route and my API with method:
Route::post('login', 'AuthController#login');
Route::post('register', 'AuthController#register');
Route::get('GetUserClaims', 'AuthController#GetUserClaims');
Route::group(['middleware' => 'auth:api'], function(){
//Route::get('details', 'AuthController#details');
//Route::get('GetUserClaims', 'AuthController#GetUserClaims');
});
http://xxx.xxx.xxx.xxx/public/api/GetUserClaims?userKey=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6Ijg3M2E4NTdhZmViMGVhMzAzNWQ5ZGU5NGZmNTUzMmI4NGUyMDZjZjE0MjRhYzQxZjI0YjUwYjdmZjc4OWZmYjM5YzhmNjBlZjRmYzM0OTQzIn0.eyJhdWQiOiIxIiwianRpIjoiODczYTg1N2FmZWIwZWEzMDM1ZDlkZTk0ZmY1NTMyYjg0ZTIwNmNmMTQyNGFjNDFmMjRiNTBiN2ZmNzg5ZmZiMzljOGY2MGVmNGZjMzQ5NDMiLCJpYXQiOjE1ODUwODU5NDksIm5iZiI6MTU4NTA4NTk0OSwiZXhwIjoxNjE2NjIxOTQ5LCJzdWIiOiI2Iiwic2NvcGVzIjpbXX0.VXKRTTpZxMGq4gR8kdu9qREBvhxSfPz4WureEYCpr-nh-qMFqkuR9Q10oa4AotmNmIABRFb_ijyrpt1AVJOpPU4b0R4lEnUWq746wh3etBg37fuSvDx8XDwF84NcOyU1GNnXDZ0KLbwr4YjrOqtuPNBAtkDEPHOKUYdxHvYOUSqt8YIx-L1p2ijHEvYDKroG8-B9mZs97HCtgSpwqTv7b5I0hEV4b1Ifkm24qDhoRMvaSYDFGcu52VWfwPjMEq6NPDYwwBx9Jpv_wv8-UA8BZPqECzE-D7xw46X4IhUNg9PyGxhtWbMvipz1E1OFzb_lBmgYTU5JVx0s0wmmcjqAq4jlfHNarUdBQGziJR4m3rLBGYNtLmqQ4kR1knrhaR-qQYaKiQNknxtb7c_HG724G_XSYkzFJZUalLFtQkDYpXSSP-QgzKFrQHblE6Led2AwPqt4S4svDOht5hqg29TejNbggIztj_fs9u2cwso1VvPjAM1LLG8chzVT5PM6YTihDGaVf4VEUaQmClgG64pEq2TmJISTLsplqlG1wn2BTdmCcO69VZYBvLJvjDlm942RGAYaNHD7Wt3RbJxMOH3RF8OGRP_H2IvIwtWz4x29dDUg8fMEKlA-nM1A8wsrK-YFkbwrY-IOzHl-4MdPopmXiFViB5RPMkQdCMd0ItWTjgA
public function GetUserClaims(Request $request)
{
if ( $request->has('userKey') ){
$user = Auth::user();
$token = $request->userKey;
var_dump($user);
//$token='Bearer '.$request->bearerToken();
//$request->header('Authorization',$token);
//return response()->json(['user' => auth()->user()], 200);
//return response()->json(['success' => $user], Response::HTTP_OK);
}
}
I think you can refer to the solution below to solved you issue.
Laravel 7 filters
The guide lead you about how to setup Laravel Authentication which include at Laravel package.
You don't have to build out from scratch by yourself
I have user cars having many to many relation between users and cars. I am using passport and everthing is working properly (Sign-in, Sign-up etc) In my I have a method like below in Users Model
public function cars()
{
return $this->belongsToMany(Car::class, 'users_cars', 'user_id', 'car_id');
}
I also have API auth routes which is working fine
Route::group([
'prefix' => 'auth'
], function () {
Route::post('login', 'AuthController#login');
Route::post('signup', 'AuthController#signup');
Route::group([
'middleware' => 'auth:api'
], function() {
Route::get('logout', 'AuthController#logout');
Route::get('user', 'AuthController#user');
Route::get('car-list','CarController#carList');
});
});
And in CarController I am trying to get user cars based on auth login user_id as like below
public function carList(){
$User = new User();
return new CarResource($User->cars());
}
I am also using API resource for API's
use App\Http\Resources\Car as CarResource;
But it does not working so can someone kindly guide me how to fix the issue. I would appreciate, thank you so much.
In the CarController you are instantiating a new User object. They are never going to have any cars. If you want to get all the cars that the user who is logged in, you will need to do something like the following:
public function carList(){
$User = User::with('cars')->findOrFail(Auth::id());
return new CarResource($User->cars);
}
How am I able to maintain or create a session through Ajax login. I have a Laravel installation not that much different from a basic make:auth installation.
I had to ovewrite some parts of the authcontroller to return json instead of redirects. Here's the login part:
/**
* Handle an authentication attempt.
*
* #return Response
*/
public function login(Request $request)
{
$this->validate($request, [
$this->loginUsername() => 'required',
'password' => 'required'
]);
// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
$throttles = $this->isUsingThrottlesLoginsTrait();
if ($throttles && $this->hasTooManyLoginAttempts($request)) {
// to many attempts
if ( $request->ajax() )
{
$this->response['code'] = 406;
$this->response['message'] = $this->sendLockoutResponse($request);
return response()->json($this->response);
}
return $this->sendLockoutResponse($request);
}
$credentials = $this->getCredentials($request);
$credentials['is_active'] = 1;
if (Auth::attempt($credentials, $request->has('remember'))) {
// succes
return $this->handleUserWasAuthenticated($request, $throttles);
}
// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
if ($throttles) {
$this->incrementLoginAttempts($request);
}
// error
if ( $request->ajax() )
{
$this->response['code'] = 406;
$this->response['message'] = $this->getFailedLoginMessage();
return response()->json($this->response);
}
return redirect()->back()
->withInput($request->only($this->loginUsername(), 'remember'))
->withErrors([
$this->loginUsername() => $this->getFailedLoginMessage()
]);
}
/**
* Handle an authenticated response.
*
* #return Response
*/
public function authenticated($request, $user)
{
if ( $request->ajax() )
{
$this->response['message'] = "success";
return response()->json($this->response);
}
else
{
return redirect()->intended($this->redirectPath());
}
}
Here are the routes used:
Route::group(['namespace' => 'Auth'], function() {
Route::post('/login', ['uses' => 'AuthController#login', 'as' => 'login']);
Route::post('/registreer', ['uses' => 'AuthController#postRegister', 'as' => 'register']);
Route::post('/reset', ['uses' => 'PasswordController#sendResetLinkEmail', 'as' => 'reset']);
});
I am working with Vue.js in the frontend which get the error and succes responses perfectly. Only after refreshing the browser i am not in a logged in state. How am I able to do this.
There's no session when you are working with AJAX / JSON REST APIs. Instead of sessions, REST APIs use tokens / some kind of authentication.
If you are building a REST API and using VueJS as the front end framework for a single page application, use the api middleware instead of the default web middleware.
Read more information about JSON Web Tokens here:
https://jwt.io/introduction/
You are basically creating a stateless application when you are using Ajax. The frontend side basically didnt need to know the state of the user, wether he is already login or not. So you didnt need any session.
What you need to do is get information from the server wether your user is authorized to get any resource on the server. This is basically Authenticating (the process to validate user credential that being sent to the server and then returning sort of id to the user) and Authorization the process to check wether the id is authorized to access the resource requested.
I guess i declared my question not properly because of the misunderstandings. However i did get it to work. The fix is to put middleware around the specific routes. Now I am to login trough a Ajax request.
Route::group(['middleware' => 'web'], function () {
...
});