How to verifiy JWT on a single route in Laravel - laravel

I have a single route in Laravel on which I need to verify the JWT on header if it is authorized and not expired. How can I do that?
In Javascript its really easy, but don`t know how in Laravel.
Here's the code:
public function update(Request $request){
$header = $request->header('Authorization');
$token = $request->bearerToken();
$secret = env('EXAMPLE_SECRETE');
$verified = here i want to verify the jtw /$token
if (!verified)
return 'something here'
else
>>code here after verified
}

First of install below package
composer require firebase/php-jwt
And then you can create a middleware in order to verify Token or expired, below is a complete code of middlware
namespace App\Http\Middleware;
use Closure;
use Exception;
use App\User;
use Firebase\JWT\JWT;
use Firebase\JWT\ExpiredException;
class JwtTokenMiddleware
{
public function handle($request, Closure $next, $guard = null)
{
$token = $request->bearerToken();
if (!$token) {
// Unauthorized response if token not there\
}
try {
$credentials = JWT::decode($token, env('JWT_SECRET'), ['HS256']);
//You can get credentials that you have set up while generating token
$user = User::findOrFail($credentials->sub)->setAuthUser();
$request->auth = $user;
} catch (ExpiredException $e) {
// Token expired response
} catch (Exception $e) {
// Handle unknow error while decoding token
return response()->json([
}
return $next($request);
}
}

Related

Authorize function is not working with middleware | Laravel

I have an authorization using middleware where Function could only run when authorized
this is my middleware:
class IsAdmin
{
public function handle($request, Closure $next)
{
if (auth()->check() && auth()->user()->is_admin == 1) {
return $next($request);
}
return abort(403, 'Forbidden');
}
}
my Controller:
public function destroy(int $bookId, int $reviewId, Request $request)
{
// #TODO implement
$check_bookReview = BookReview::firstWhere('id', $reviewId)->where('book_id', $bookId);
if ($check_bookReview && isAdmin()) {
BookReview::destroy($reviewId);
return response()->noContent();
} else {
abort(404);
}
}
and my api.php as well my Kernel:
'auth.admin' => \App\Http\Middleware\IsAdmin::class
Route::group(['middleware' => ['auth.admin']], function (){
Route::post('/books', 'BooksController#store');
Route::post('/books/{id}/reviews', 'BooksReviewController#store');
Route::delete('/books/{bookId}/reviews/{reviewId}', 'BooksReviewController#destroy');
});
and i have a User db field where it contains api_token and is_admin like below:
and my Postman still return 403 forbidden while i already gave an authorization by headers:
what should i do here, to fulfill my function?
Looks like your Authenticate middleware is not working, so it likely fails on auth()->check().
Make sure to use the auth middleware from Laravel, you can also use a guard as described here:
https://laravel.com/docs/9.x/authentication#protecting-routes

User Authentication With Flutter API

I got my backend with Laravel and My Api looks like this :
Route::apiresource('/user','App\Http\Controllers\api\UserController');
And this is my UserController :
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use DB;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
class UserController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
//
$user = DB::table('users')->get();
return response()->json($user);
}
I want to know how can I check if the email and a password in a Flutter screen match my DB records when I hit login button.
This is what I've done so far now in My Flutter :
Future<User> fetchUser() async {
final response = await http
.get(Uri.parse('http://127.0.0.1:8000/api/user'));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
if(response.body.isNotEmpty) {
json.decode(response.body);
}
return User.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load user');
}
}
And of course ,I got my form with 2 inputs Email and password .
From what I understand, I think you want to authenticate your user in the api. This page of the documentation is very easy to understand. If the user credentials match, you could return the user and create a token with laravel sanctum or Passport for the further requests for example :
// With laravel santum
if(Auth::attempt($signInRequest->only(['email', 'password']), true))
{
$user = Auth::user();
$token = $user->createToken($signInRequest->input('device_name'))->plainTextToken;
return response()->json([
'user' => $user,
'token' => $token
]);
}
return response()->json(['message' => 'Auth failed'], 401);

GoToWebinar Webhook Signature verification fails

I am trying to verify webhook signature for GoToWebinar webinar.created event.
Docs: https://developer.goto.com/guides/HowTos/08_HOW_webhooks/
My Middleware (Laravel):
public function handle(Request $request, Closure $next)
{
if (! $this->verifyGoToWebinarWebhookSignature($request)) {
abort(401);
}
return $next($request);
}
private function verifyGoToWebinarWebhookSignature(Request $request):bool
{
return ($request->header('x-webhook-signature') == $this->calculateHmac($request));
}
private function calculateHmac(Request $request):string
{
$secret = '12345';
$signature = $request->header('x-webhook-signature-timestamp');
$payload = json_encode($request->all(), true);
$signaturePayload = $signature . ':' . $payload;
return base64_encode(hash_hmac('sha256', $signaturePayload, $secret, true));
}
The comparison always returns false. Tested on real data. Can't figure out what I did wrong.
Was using the wrong secret, the API allows to create multiple secret keys but if you do not store them there is not way to match them to the x-webhook-secretkey-id in the request header.

how to change "CSRF token mismatch" message?

I'm using larvel 8 and want to change message of "CSRF token mismatch" when using ajax post. I created a closure and passed it to the renderable method on the App\Exceptions\Handler class, but the previews message appears.
This is my code:
use Illuminate\Session\TokenMismatchException;
class Handler extends ExceptionHandler
{
protected $dontReport = [
//
];
protected $dontFlash = [
'password',
'password_confirmation',
];
public function register()
{
$this->renderable(function (TokenMismatchException $e, $request) {
return $request->expectsJson()
? response()->json(['message' => 'A new message...'], 419)
: redirect()->guest(route('login'));
});
}
To modify error message on TokenMismatchException both for web-pages and ajax-requests
It would be better to overload prepareException() method in application exception handler:
protected function prepareException(Exception $e)
{
if ($e instanceof TokenMismatchException) {
$e = new HttpException(419, __('exception.csrf_token_mismatch'), $e);
}
return parent::prepareException($e);
}
So you can create translation file and modify message by language files. For example create resources/lang/en/exception.php with content below:
<?php
return [
'csrf_token_mismatch' => 'CSRF token mismatch. Please, refresh page (CTRL+R) and try again.',
];
thanks to everyone who contributed, I found the solution.
Due to laravel change the TokenMismatchException to HttpException in the function prepareException in the Illuminate\Foundation\Exceptions\Handler class(parent of Handler class), we cannot render the TokenMismatchException.
protected function prepareException(Throwable $e)
{
if ($e instanceof ModelNotFoundException) {
$e = new NotFoundHttpException($e->getMessage(), $e);
} elseif ($e instanceof AuthorizationException) {
$e = new AccessDeniedHttpException($e->getMessage(), $e);
} elseif ($e instanceof TokenMismatchException) {
$e = new HttpException(419, $e->getMessage(), $e);
} elseif ($e instanceof SuspiciousOperationException) {
$e = new NotFoundHttpException('Bad hostname provided.', $e);
} elseif ($e instanceof RecordsNotFoundException) {
$e = new NotFoundHttpException('Not found.', $e);
}
return $e;
}
I modify my renderable method as below and now I can catch the TokenMismatchException:
$this->renderable(function (HttpException $e, $request) {
if ($e->getPrevious() instanceof TokenMismatchException) {
return $request->expectsJson()
? response()->json(['message' =>'Your new message ...', 419)
: redirect()->guest(route('login'));
}
});
If you want to change the error message or the page that is shown when CSRF token mismatch happen
Run this command: php artisan vendor:publish --tag=laravel-errors
It will publish your default (vendor) exceptions page to resources/views/errors/
From there, edit resources/views/errors/419.blade.php with html that you would like to show when CSRF verification error happen.
References: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
419 Page Expired (Laravel Framework)
Used by the Laravel Framework when a CSRF Token is missing or expired.
If you want to allow ajax requests to bypass CSRF token verification
Reference: https://laravel.com/docs/8.x/csrf#csrf-excluding-uris
Edit your VerifyCsrfToken middleware (location: app/Http/Middleware/VerifyCsrfToken.php), add:
class VerifyCsrfToken extends Middleware
{
/**
* The URIs that should be excluded from CSRF verification.
*
* #var array
*/
protected $except = [
'stripe/*',
'http://example.com/foo/bar',
'http://example.com/foo/*',
];
}

JWT Authentication user_not_found Tymon

I have set up Tymon Package for JWT Authentication. In case of new user sign up or login I get the token successfully. But when I pass the token to the Laravel JWT I get an error as user not found.
controller code
public function authenticate()
{
$credentials = request()->only('user_name','password');
try{
$token = JWTAuth::attempt($credentials);
if(!$token){
return response()->json(['error'=>'invalid_credentials'],401);
}
}
catch(JWTException $e){
return response()->json(['error'=>'something went wrong'],500);
}
return response()->json(['token'=>$token],200);
}
public function register()
{
$user_name = request()->user_name;
$c_name = request()->company_name;
$accessibility_level = request()->accessability_level;
$password = request()->password;
$contact_number = request()->contact_number;
$address = request()->address;
$user = User::create([
'user_name'=>$user_name,
'c_name'=>$c_name,
'accessibility_level'=>$accessibility_level,
'password'=>bcrypt($password),
'contact_number'=>$contact_number,
'address'=>$address
]);
$token = JWTAuth::fromUser($user);
return response()->json(['token'=>$token],200);
}
no problem with the above code works fine.
But when I try to access some data with JWT validation I get an error as USER_NOT_FOUND. I have passed the Token which I have got as an header through Postman.
Route Code
Route::get('/some_route','some_controller#index')->middleware('jwt.auth');
And the jwt.php is also set with the correct identifier which I have used in the model(Primary key)
'identifier' => 'user_name',
The JWT identifier doesn't work by simply modifying the config because it's hardcoded as id in the code for some reason
You can of course use the setIdentifier method before calling any other JWTAuth methods to set the identifier.
Here's how:
public function authenticate()
{
$credentials = request()->only('user_name','password');
try{
$token = JWTAuth::setIdentifier('user_name')->attempt($credentials);
if(!$token){
return response()->json(['error'=>'invalid_credentials'],401);
}
}
catch(JWTException $e){
return response()->json(['error'=>'something went wrong'],500);
}
return response()->json(['token'=>$token],200);
}
Then create a custom middleware for jwt authentication:
public function handle($request, \Closure $next)
{
if (! $token = $this->auth->setIdentifier('user_name')->setRequest($request)->getToken()) {
return $this->respond('tymon.jwt.absent', 'token_not_provided', 400);
}
try {
$user = $this->auth->authenticate($token);
} catch (TokenExpiredException $e) {
return $this->respond('tymon.jwt.expired', 'token_expired', $e->getStatusCode(), [$e]);
} catch (JWTException $e) {
return $this->respond('tymon.jwt.invalid', 'token_invalid', $e->getStatusCode(), [$e]);
}
if (! $user) {
return $this->respond('tymon.jwt.user_not_found', 'user_not_found', 404);
}
$this->events->fire('tymon.jwt.valid', $user);
return $next($request);
}

Resources