I have already written an API call for check authentication using Laravel. I need to move that controller to Lumen for use it as micro service.
This is my controller in Laravel.
public function byCredantial(Request $request)
{
$user = [
'email' => $request->input('email'),
'password' => $request->input('password')
];
if (Auth::attempt($user)) {
$response = $this->getSuccess(Auth::user()->id);
return response()->json($response, 200);
} else {
$response = $this->getError($user);
return response()->json($response, 401);
}
}
Lumen doc is not provide how to do such authentication. They has not function for check creadential is correct. How can i do this in Lumen. Is this possible?
You can do this in Lumen. Facades are disabled by default (if you want to enable it you can see the instructions in the documentation), but I would not recommend enabling the facades as the add additional overhead to your application. Instead, I would modify your function to call app('auth'). This will return the class that the Auth facade proxies without loading all the other facades.
public function byCredantial(Request $request)
{
$user = [
'email' => $request->input('email'),
'password' => $request->input('password')
];
$auth = app('auth');
if ($auth->attempt($user)) {
$response = $this->getSuccess($auth->user()->id);
return response()->json($response, 200);
} else {
$response = $this->getError($user);
return response()->json($response, 401);
}
}
Also, I would recommend reading the authentication documentation and placing the bulk of this code in the AuthServiceProvider.
Related
Using the authentication plugin, I'm unable to verify my credentials via json. I can use Form, Jwt and Basic(For testing it works). The error returned is 'FAILURE_CREDENTIALS_INVALID'. Here's the sample code "simplified for brevity"
public function token()
{
$result = $this->Authentication->getResult();
if ($result->isValid()) {
//new jwt token etc
$message = true;
$this->log($result->getStatus());
}else{
$message = false;
$this->log($result->getStatus());
}
$this->set([
'message' => $message,
]);
$this->viewBuilder()->setOption('serialize', ['message']);
}
My application class has the method
public function getAuthenticationService(ServerRequestInterface $request) : AuthenticationServiceInterface
{
$service = new AuthenticationService();
$service->setConfig([
'unauthenticatedRedirect' => '/users/login',
'queryParam' => 'redirect',
]);
$fields = [
'username' => 'email',
'password' => 'password'
];
// Load the authenticators, you want session first
$service->loadAuthenticator('Authentication.Session');
$service->loadAuthenticator('Authentication.Form', [
'fields' => $fields,
'loginUrl' => '/users/login'
]);
//Testing jwt
$service->loadAuthenticator('Authentication.Jwt', [
'secretKey' => Security::getSalt()]);
// Load identifiers
$service->loadIdentifier('Authentication.Password', compact('fields'));
$service->loadIdentifier('Authentication.JwtSubject');
return $service;
}
The app is serving some json well if I pass in the jwt, but somehow I can't figure out how to request a new one, when the old expires.
Here's my middlewareQueue:
//some code
$middlewareQueue
->add(new ErrorHandlerMiddleware(Configure::read('Error')))
->add(new AssetMiddleware([
'cacheTime' => Configure::read('Asset.cacheTime'),
]))
->add(new RoutingMiddleware($this))
->add($csrf)
->add(new BodyParserMiddleware())
->add(new AuthenticationMiddleware($this));
//more code
I DO NOT use basic
As mentioned in the comments, if you want to authenticate using the form authenticator on your token retrieval endpoint, then you need to make sure that you include the URL path of that endpoint in the authenticators loginUrl option.
That option accepts an array, so it should be as simple as this:
$service->loadAuthenticator('Authentication.Form', [
'fields' => $fields,
'loginUrl' => [
'/users/login',
'/api/users/token.json',
],
]);
The error that you were receiving was because the form authenticator simply wasn't applied on the token endpoint, and therefore the authentication service would go to the next authenticator, the JWT authenticator, which isn't bound to a specific endpoint, and therefore can run for all endpoints, and the JWT authenticator of course expects a different payload, it looks for a token, and if it can't find it, it will return the error status FAILURE_CREDENTIALS_INVALID.
auth:api middleware not working in live server using laravel
Route::group(['prefix' => 'business_entry_api','middleware' => 'auth:api'], function () {
// function here
}
you ca go with auth('api')->user(). It'll return the authenticated user even if middleware is not specifically used.
use like below on your api file:
public function __construct()
{
$this->middleware(function ($request,Closure $next) {
$this->user = Auth('api')->user();
return $next($request);
});
}
I am new to both laravel and lumen.
I was creating a login api with oauth2.0 in lumen 5.6, i have installed passport and generated token.
Below is my login controller function and it is working fine. It returns token.
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Route;
//use Illuminate\Support\Facades\DB;
use App\User;
use Auth;
public function login(Request $request)
{
global $app;
$proxy = Request::create(
'/oauth/token',
'post',
[
'grant_type' => env('API_GRAND_TYPE'),
'client_id' => env('API_CLIENT_ID'),
'client_secret' => env('API_CLIENT_SECRET'),
'username' => $request->username,
'password' => $request->password,
]
);
return $app->dispatch($proxy);
}
Since i have to check user status apart from username and password, i need to check the user credential first. so i do like this.
public function login(Request $request)
{
$credentials = $request->only('username', 'password');
if (Auth::attempt($credentials)) {
return ['result' => 'ok'];
}
return ['result' => 'not ok'];
}
Here i am getting this error.
Method Illuminate\Auth\RequestGuard::attempt does not exist.
So i tried Auth::check instead of Auth::attempt.
Now there is no error but it always return false even though the credentials are valid.
I searched a lot for a solution but i didn't get.
The function guard is only available for routes with web middleware
public function login() {
if(Auth::guard('web')->attempt(['email' => $email, 'password' => $password], false, false)) {requests
// good
} else {
// invalid credentials, act accordingly
}
}
Changing default guard to "web" fixed my problem.
config/auth.php:
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
using jwt it's worked for me
1-Auth::attempt($credentials)
just replace line 1 to line 2
2-$token = Auth::guard('api')->attempt($credentials)
How to send send error message in json format to postman in laravel 5.4
//Controller
public function store(Request $request)
{
$validator = Validator::make($request->all(),[
'department_name' => 'required',
]);
if($validator->fails())
{
return $validator->errors()->all();
}
Department::create($request->all());
return Response::json(['message' => 'Added','status' => 201],201);
}
You can simply return the validation errors as json response like this :
if ($validator->fails()) {
return response()->json(['errors'=>$validator->errors()]);
}
I want to have JWT authentication in Laravel >=5.2, using this (Tymon JWT-auth) library but I want to put JWT token into HttpOnly Cookies - to protect JWT token from steal from XSS attack.
I set up Tymon library and... in project: app/Providers/RouteServiceProvider#mapWebRoutes i deactivate execution 'web' middelware group for all requests (which is default laravel behavior - you can see it by php artisan route:list) by remove 'middleware' => 'web' (If I don't do it, i will see CSRF problem with post request).
in routes.php i write:
Route::group(['middleware' =>'api', 'prefix' => '/api/v1', 'namespace' => 'Api\V1'], function () {
Route::post('/login', 'Auth\AuthController#postLogin');
...
Route::get('/projects', 'ProjectsController#getProjects');
}
In may Api\V1\Auth\AuthController#postLogin i generate token and send it back as httpOnly cookie:
...
try
{
$user = User::where('email','=',$credentials['email'])->first();
if ( !($user && Hash::check($credentials['password'], $user->password) ))
{
return response()->json(['error' => 'invalid_credentials'], 401);
}
$customClaims = ['sub' => $user->id, 'role'=> $user->role, 'csrf-token' => str_random(32) ];
$payload = JWTFactory::make($customClaims);
$token = JWTAuth::encode($payload);
} catch(...) {...}
return response()->json($payload->toArray())->withCookie('token', $token, config('jwt.ttl'), "/", null, false, true);
And, yeah here question starts. I would like to do something (may be modifiy laravel Auth class) on each request:
get coookie from request
decode it
check is right (if not trhow 401)
get user from DB
and make that method Auth::user() works every where like in usual way in laravel (so i can use it in each Controller for example)
Any ideas how to do point 4 ?
UPDATE
I also add here protection for CSRF attack - csrf-token is in JWT, and it is also return in body of response for login request (so JS have acces to this csrf-token) (i return only public part of JWT token in login response, whole JWT is return only in cookie, so it is XSS safe) - then front JS must copy csrf-token into header of each request. Then the middelware JWTAuthentiacate (in my answer below) compare csrf-token header with csrf-token field in JWT payload - if they are similar then request pass csrf test.
You can do it simple by creating middleware.
In handle() method just get cookie from request, decode it and login a user using id with this Laravel method:
Auth::loginUsingId($userIdFromToken);
I implement #ĆukaszKuczmaja idea in this way an it works! :) . So i create file in app/Http/Middleware/JWTAuthenticate.php :
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
use JWTAuth;
use Tymon\JWTAuth\Token;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use Illuminate\Session\TokenMismatchException;
class JWTAuthenticate
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string|null $guard
* #return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
try {
if(!$request->headers->has('csrf-token')) throw new TokenMismatchException();
$rawToken = $request->cookie('token');
$token = new Token($rawToken);
$payload = JWTAuth::decode($token);
if($payload['csrf-token'] != $request->headers->get('csrf-token')) throw new TokenMismatchException();
Auth::loginUsingId($payload['sub']);
} catch(\Exception $e) {
if( $e instanceof TokenExpiredException) {
// TODO token refresh here
}
return response('Unauthorized.', 401);
}
return $next($request);
}
}
In app\Http\Kernel.php#$routeMiddelware I add line:
'jwt.auth' => \App\Http\Middleware\JWTAuthenticate::class,
My routing file looks like this now:
Route::group(['middleware' =>'api', 'prefix' => '/api/v1', 'namespace' => 'Api\V1'], function () {
Route::post('/login', 'Auth\AuthController#postLogin');
Route::group(['middleware' =>'jwt.auth'], function () {
Route::post('/projects', 'ProjectsController#postProjects');
Route::get('/projects', 'ProjectsController#getProjects');
Route::put('/projects/{project}', 'ProjectsController#putProjects');
Route::delete('/projects/{project}', 'ProjectsController#deleteProjects');
});
});
And for instance in app/Http/Controllers/Api/V1/ProjectsController.php i have:
public function getProjects() {
$uid = Auth::user()->id;
return Project::where('user_id','=',$uid)->get();
}
Actually you can put every route that needs authentication within a route group and add the middleware like this:
Route::group(['middleware' => ['jwt.auth']], function () {
Route::patch('/profile', 'UserController#update');
});
The middleware already does what you wanted so there is no need to write additional logic. Don't use an additional handle method.
Within your i.e. UserController you can then i.e.
$user = \Auth::user();
And i.e. depending what you need...
// assign fields
$user->save();
return 'success'; // or whatever you need
Don't reinvent the wheel and keep things DRY.