How to generate JWT refresh token in Laravel 5.7 - laravel

First off, let me admit that I'm new to APIs, and right now I'm working on JWT with Laravel. I'm using tymon\jwt-auth (tymon/jwt-auth:dev-develop --prefer-source to be specific). I went through some tutorials and was able to generate JWT access token.
Here is my login code:
public function login() {
$credentials = request(['email', 'password']);
if (!$token = auth('api')->attempt($credentials)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
return response()->json([
'status' => 'success',
'message' => 'Login successful',
'data' => [
'access_token' => $token,
],
]);
}
I also need to get refresh token along with the access token, and cannot find code that works in my case.
I tried adding these lines in the code:
$refresh_token = JWTAuth::refresh($token);
but the postman returns with this error:
A token is required in file
/var/www/brochill-api/vendor/tymon/jwt-auth/src/JWT.php on line 331
I can also provide other configuration snippets I used if needed. Please help!

Let's start with creating a /refresh route:
Route::post('refresh', 'AuthController#refresh');
Now, in the AuthController,
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Controller;
class AuthController extends Controller
{
/**
* Create a new AuthController instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth:api', ['except' => ['login']]);
}
/**
* Get a JWT via given credentials.
*
* #return \Illuminate\Http\JsonResponse
*/
public function login()
{
//
}
/**
* Get the authenticated User.
*
* #return \Illuminate\Http\JsonResponse
*/
public function me()
{
//
}
/**
* Log the user out (Invalidate the token).
*
* #return \Illuminate\Http\JsonResponse
*/
public function logout()
{
//
}
/**
* Refresh a token.
*
* #return \Illuminate\Http\JsonResponse
*/
public function refresh()
{
return $this->respondWithToken(auth()->refresh());
}
/**
* Get the token array structure.
*
* #param string $token
*
* #return \Illuminate\Http\JsonResponse
*/
protected function respondWithToken($token)
{
return response()->json([
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => auth()->factory()->getTTL() * 60
]);
}
}
The refresh() function refreshes the access token and invalidates the current one.
For more info on these, you can checkout the official documentation of tymon/jwt-auth, which can be found here.

Related

Wrong on login and restet pasword on LARAVEL 9

enter image description here
Login is failed, the credencials email and password, is correct, but laravel dont acces to dashboard
The password reset is worng to, the email is correct and i try chance of credentials on myphpadmin but dont entry.
this is my code
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Http\Requests\Auth\LoginRequest;
use App\Providers\RouteServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class AuthenticatedSessionController extends Controller
{
/**
* Display the login view.
*
* #return \Illuminate\View\View
*/
public function create()
{
return view('auth.login');
}
/**
* Handle an incoming authentication request.
*
* #param \App\Http\Requests\Auth\LoginRequest $request
* #return \Illuminate\Http\RedirectResponse
*/
public function store(LoginRequest $request)
{
$request->authenticate();
$request->session()->regenerate();
return redirect()->intended(RouteServiceProvider::HOME);
}
/**
* Destroy an authenticated session.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\RedirectResponse
*/
public function destroy(Request $request)
{
Auth::guard('web')->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect('/');
}
}
If you're mass assignment while attempting authentication make sure the form requested keys must same as Model's $fillable keys.
then try this:
/**
* Handle an incoming authentication request.
*
* #param \App\Http\Requests\Auth\LoginRequest $request
* #return \Illuminate\Http\RedirectResponse
*/
public function store(LoginRequest $request)
{
$credentials = $request->validated();
if (Auth::attempt($credentials)) {
return redirect()->intended(RouteServiceProvider::HOME);
}
return back()->with('message', 'The given credentials are not matched');
}
if you're working with multi guards, try this:
public function store(LoginRequest $request)
{
$credentials = $request->validated();
if (Auth::guard('web')->attempt($credentials)) {
return redirect()->intended(RouteServiceProvider::HOME);
}
return back()->with('message', 'The given credentials are not matched');
}
I have tested this example code from your and my implementation
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Http\Requests\Auth\LoginRequest;
use App\Providers\RouteServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use Hash;
use Session;
use App\Models\User;
class AuthenticatedSessionController extends Controller
{
/**
* Display the login view.
*
* #return \Illuminate\View\View
*/
public function create()
{
return view('auth.login');
}
/**
* Handle an incoming authentication request.
*
* #param \App\Http\Requests\Auth\LoginRequest $request
* #return \Illuminate\Http\RedirectResponse
*/
public function store(LoginRequest $request)
{
$request->validate([
'email' => 'required',
'password' => 'required',
]);
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials)) {
return redirect()->intended('dashboard')
->withSuccess('Signed in');
}
return redirect("login")->withSuccess('Login details are not valid');
}
/**
* Destroy an authenticated session.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\RedirectResponse
*/
public function destroy(Request $request)
{
Session::flush();
Auth::logout();
return redirect('/');
}
/**
* Registration page.
*
*/
public function registration()
{
return view('auth.registration');
}
/**
* Store new user request handler
*
*/
public function storeUser(Request $request)
{
$request->validate([
'name' => 'required',
'email' => 'required|email|unique:users',
'password' => 'required|min:6',
]);
$data = $request->all();
$check = $this->create($data);
return redirect("dashboard")->withSuccess('have signed-in');
}
/**
* Store new user
*
*/
public function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password'])
]);
}
/**
* Dashboard for user
*
*/
public function dash()
{
if(Auth::check()){
return view('dashboard');
}
return redirect("login")->withSuccess('are not allowed to access');
}
}
Please check from your project and check flash messages if password was wrong check password hashing correctly

Laravel JWT makes new request insted of sending status

I'm making an API in laravel with tymon/jwt-auth package. based on https://jwt-auth.readthedocs.io/en/develop/
Login works fine.
Sending GET request with right token works fine.
BUT when I send a GET request with incorrect/no token it redirects me to POST login (wants me to login) rather than send a 401
GET /api/reviews with no Auth:
The GET method is not supported for this route. Supported methods: POST.
api.php
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
Route::group([
'prefix' => 'auth',
], function ($router) {
Route::post('login', [AuthController::class, 'login'])->name('login');
});
Route::get('reviews',[ReviewController::class, 'index']);
AuthController.php
class AuthController extends Controller
{
/**
* Create a new AuthController instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth:api', ['except' => ['login']]);
}
/**
* Get a JWT via given credentials.
*
* #return \Illuminate\Http\JsonResponse
*/
public function login()
{
$credentials = request(['email', 'password']);
if (!$token = auth()->attempt($credentials)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
return response()->json([
"user" => auth()->user(),
"access_token" => $token,
]);
}
/**
* Get the authenticated User.
*
* #return \Illuminate\Http\JsonResponse
*/
public function me()
{
return response()->json(auth()->user());
}
/**
* Log the user out (Invalidate the token).
*
* #return \Illuminate\Http\JsonResponse
*/
public function logout()
{
auth()->logout();
return response()->json(['message' => 'Successfully logged out']);
}
/**
* Refresh a token.
*
* #return \Illuminate\Http\JsonResponse
*/
public function refresh()
{
return $this->respondWithToken(auth()->refresh());
}
}
ReviewController.php
class ReviewController extends Controller
{
public function __construct()
{
$this->middleware('auth:api');
}
public function index()
{
$reviews = Review::all();
return response()->json([
'status' => 200,
'reviews' => $reviews
]);
}
}
Should I remove the auth middleware and do it manually?

Laravel jwt returns 500, on unauthorized

I use jwt for my api authentication. when I use wrong token it returns 500 and I get the error that rout login is not defiend!
I'm using laravel 8 and "tymon/jwt-auth": "^1.0". my default guard is api and api driver is jwt.
I tried name login route as login, bu then I get error that get method is not supported for this route but I'm using Post method!
rout : api.php:
Route::group(['prefix'=>'v1'],function (){
Route::group([
'middleware' => 'api',
'prefix' => 'auth'
], function ($router) {
Route::post('login', 'App\Http\Controllers\AuthController#login');
Route::post('logout', 'App\Http\Controllers\AuthController#logout');
Route::post('refresh', 'App\Http\Controllers\AuthController#refresh');
Route::post('me', 'App\Http\Controllers\AuthController#me');
});
});
AuthController:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Controller;
class AuthController extends Controller
{
/**
* Create a new AuthController instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth:api', ['except' => ['login']]);
}
/**
* Get a JWT via given credentials.
*
* #return \Illuminate\Http\JsonResponse
*/
public function login()
{
$credentials = request(['email', 'password']);
if (! $token = auth()->attempt($credentials)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
return $this->respondWithToken($token);
}
/**
* Get the authenticated User.
*
* #return \Illuminate\Http\JsonResponse
*/
public function me()
{
return response()->json(auth()->user());
}
/**
* Log the user out (Invalidate the token).
*
* #return \Illuminate\Http\JsonResponse
*/
public function logout()
{
auth()->logout();
return response()->json(['message' => 'Successfully logged out']);
}
/**
* Refresh a token.
*
* #return \Illuminate\Http\JsonResponse
*/
public function refresh()
{
return $this->respondWithToken(auth()->refresh());
}
/**
* Get the token array structure.
*
* #param string $token
*
* #return \Illuminate\Http\JsonResponse
*/
protected function respondWithToken($token)
{
return response()->json([
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => auth()->factory()->getTTL() * 60
]);
}
}
user model:
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Tymon\JWTAuth\Contracts\JWTSubject;
class User extends Authenticatable implements JWTSubject
{
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
// Rest omitted for brevity
/**
* Get the identifier that will be stored in the subject claim of the JWT.
*
* #return mixed
*/
public function getJWTIdentifier()
{
return $this->getKey();
}
/**
* Return a key value array, containing any custom claims to be added to the JWT.
*
* #return array
*/
public function getJWTCustomClaims()
{
return [];
}
}
error that I get:
Symfony\Component\Routing\Exception\RouteNotFoundException: Route [login] not defined. in file C:\wamp64\www\medrep-app\vendor\laravel\framework\src\Illuminate\Routing\UrlGenerator.php on line 444
🧨 Route [login] not defined
Try to change your routes, by adding a route name, and Add a GET request for route.
Route::group(['prefix'=>'v1'],function (){
Route::group([
'middleware' => 'api',
'as' => 'api.',
'prefix' => 'auth'
], function ($router) {
Route::post('login', 'App\Http\Controllers\AuthController#login')->name('login');
Route::get('login', 'App\Http\Controllers\AuthController#sessionExpired')->name('sessionExpired');
Route::post('logout', 'App\Http\Controllers\AuthController#logout')->name('logout');
Route::post('refresh', 'App\Http\Controllers\AuthController#refresh')->name('refresh');
Route::post('me', 'App\Http\Controllers\AuthController#me')->name('me');
});
});
The login & sessionExpired function may have this code as exemple:
public function login()
{
dd('test token');
$credentials = request(['email', 'password']);
if (! $token = auth()->attempt($credentials)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
return $this->respondWithToken($token);
}
public function sessionExpired()
{
return response()->json(['error' => 'session expired'],401);
}
In Postman make sure you are using POST method:

Email verification in laravel when using api routes

I have created laravel api for angular application to register user this is the Registration code and it is working but i want to verify user email after user is registered. I have used laravel default laravel verification in web but i don't have idea of using it in api.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Models\User;
use Illuminate\Auth\Events\Verified;
use Validator;
class AuthController extends Controller
{
public function __construct() {
$this->middleware('auth:api', ['except' => ['login', 'register']]);
}
/**
* Get a JWT via given credentials.
*
* #return \Illuminate\Http\JsonResponse
*/
public function login(Request $request){
$validator = Validator::make($request->all(), [
'email' => 'required|email',
'password' => 'required|string|min:6',
]);
if ($validator->fails()) {
return response()->json($validator->errors(), 422);
}
if (! $token = auth()->attempt($validator->validated())) {
return response()->json(['error_message' => 'Invalid Credentials'], 401);
}
return $this->createNewToken($token);
}
/**
* Register a User.
*
* #return \Illuminate\Http\JsonResponse
*/
public function register(Request $request) {
$validator = Validator::make($request->all(), [
'name' => 'required|string|between:2,100',
'email' => 'required|string|email|max:100|unique:users',
'password' => 'required|string|confirmed|min:6',
]);
if($validator->fails()){
return response()->json($validator->errors(), 422);
}
$user = User::create(array_merge(
$validator->validated(),
['password' => bcrypt($request->password)]
));
return response()->json([
'message' => 'User successfully registered',
'user' => $user
], 201);
}
/**
* Log the user out (Invalidate the token).
*
* #return \Illuminate\Http\JsonResponse
*/
public function logout() {
auth()->logout();
return response()->json(['message' => 'User successfully signed out']);
}
/**
* Refresh a token.
*
* #return \Illuminate\Http\JsonResponse
*/
public function refresh() {
return $this->createNewToken(auth()->refresh());
}
/**
* Get the authenticated User.
*
* #return \Illuminate\Http\JsonResponse
*/
public function userProfile() {
return response()->json(auth()->user());
}
/**
* Get the token array structure.
*
* #param string $token
*
* #return \Illuminate\Http\JsonResponse
*/
protected function createNewToken($token){
return response()->json([
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => auth()->factory()->getTTL() * 60,
'user' => auth()->user()
]);
}
}
User Model:
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use Tymon\JWTAuth\Contracts\JWTSubject;
class User extends Authenticatable implements JWTSubject, MustVerifyEmail
{
use HasApiTokens, HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* #var string[]
*/
protected $fillable = [
'name',
'email',
'password',
'email_verified_at'
];
/**
* The attributes that should be hidden for serialization.
*
* #var array
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* Get the identifier that will be stored in the subject claim of the JWT.
*
* #return mixed
*/
public function getJWTIdentifier() {
return $this->getKey();
}
/**
* Return a key value array, containing any custom claims to be added to the JWT.
*
* #return array
*/
public function getJWTCustomClaims() {
return [];
}
/**
* The attributes that should be cast.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
}
Please give some solution, Thanks
Option1
So one way i handle this is by checking the email_verified_at column on your user.
when a user logs in check if email_verified_at exists.
I also have a separate table called user_verification_tokens which contain a userID, token, and tokenExpiryDate
if it doesn't exist you can enforce verification by not logging them in until they verify their email. This could send a email to the user.
When the email gets generated a UUID gets inserted into the token column in the user_verification_tokens and sent through to the email. When the user clicks on the email and it checks on an unauthenticated route if that token exists then updates the email_verified_at column.
Option2
Generate a OTP that that gets sent to the email
User manually enters OTP
Verify UserID + OTP exists
Update email_verified_at

Limit login attempts in Laravel 5.2

I am created a Laravel 5.2 application; I need to limit failure login attempts.I am created a AuthController with following code; But not working logging attempt lock.
<?php
namespace App\Http\Controllers\Auth;
use App\User;
use Validator;
use Auth;
use URL;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
class AuthController extends Controller
{
use AuthenticatesAndRegistersUsers;
protected $maxLoginAttempts=5;
protected $lockoutTime=300;
/**
* Create a new authentication controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest', ['except' => 'getLogout']);
$this->loginPath = URL::route('login');
$this->redirectTo = URL::route('dashboard'); //url after login
$this->redirectAfterLogout = URL::route('home');
}
public function index()
{
return 'Login Page';
}
/**
* Handle a login request to the application.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function postLogin(Request $request)
{
$this->validate($request, [
'username' => 'required', 'password' => 'required',
]);
$throttles = $this->isUsingThrottlesLoginsTrait();
if ($throttles && $this->hasTooManyLoginAttempts($request)) {
return $this->sendLockoutResponse($request);
}
$credentials = $this->getCredentials($request);
if (Auth::attempt($credentials, $request->has('remember'))) {
return redirect()->intended($this->redirectPath());
}
if ($throttles) {
$this->incrementLoginAttempts($request);
}
return redirect($this->loginPath)
->withInput($request->only('username', 'remember'))
->withErrors([
'username' => $this->getFailedLoginMessage(),
]);
}
/**
* Get the needed authorization credentials from the request.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
protected function getCredentials(Request $request)
{
return $request->only('username', 'password');
}
/**
* Create a new user instance after a valid registration.
*
* #param array $data
* #return User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'username' => $data['username'],
'password' => bcrypt($data['password']),
]);
}
}
After many failure login their is no error message displayed. I am added some line to display error in login.blade.php file
Assuming you have implemented the make:auth artisan command of laravel.
Inside of the loginController, change the properties:
protected $maxLoginAttempts=5; to protected $maxAttempts = 5;
and
protected $lockoutTime=300; to protected $decayMinutes = 5; //in minutes
you need to use ThrottlesLogins trait in your controller
....
use AuthenticatesAndRegistersUsers, ThrottlesLogins ;
...
take a look here https://github.com/GrahamCampbell/Laravel-Throttle
and here https://mattstauffer.co/blog/login-throttling-in-laravel-5.1
Second link is for L5.1, but I think shouldnt be different for L5.2
Hope it helps!
Have a nice day.
Just overriding the following 2 functions maxAttempts and decayMinutes will be good to go. This 2 functions belong to Illuminate\Foundation\Auth\ThrottlesLogins.php file. I have tested on Laravel 5.6 version and working fine.
public function maxAttempts()
{
//Lock on 4th Failed Login Attempt
return 3;
}
public function decayMinutes()
{
//Lock for 2 minutes
return 2;
}

Resources