I used jwt-auth.
It works well in login, but when I try to register it and go through the login request the error below occurred.
"message": "Unauthenticated."
Here is the source code:
config/auth.php
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'jwt',
'provider' => 'users',
'hash' => True,
],
routes/api.php:
Route::group([
'middleware' => 'api',
'namespace' => 'App\Http\Controllers',//must include the path
'prefix' => 'auth'
], function ($router) {
Route::post('login', 'AuthController#login');
Route::post('signup', 'AuthController#signup');
Route::post('logout', 'AuthController#logout');
Route::post('refresh', 'AuthController#refresh');
Route::post('me', 'AuthController#me');
});
AuthController.php
public function __construct()
{
$this->middleware('auth:api', ['except' => ['login,signup']]);
}
public function login()
{
$credentials = request(['email', 'password']);
if (! $token = auth()->attempt($credentials)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
return $this->respondWithToken($token);
}
public function signup(Request $request){
$validation = $request->validate([
'email' =>'required',
'name' =>'required',
'password'=>'required|min:6|confirmed',
]);
$data = array();
$data['name'] = $request->name;
$data['email'] = $request->email;
$data['password'] = Hash::make($request->password);
DB::table('users')->insert($data);
return $this->login($request);
}
I provided DB and Hash classes. In postman, I put the route in the POST method and set headers Accept and content-type as application/json formate and in the body part, I set x-www-form and input all the keys and values with confirmation_password key. It not inserting into the database and showing the error message. I tried it by clearing the config cache and route cache. I also tried it with raw and json format.
i think you problem with ur constractor middleware u didn't make the except value right u have to make to different values for except like that
$this->middleware('auth:api', ['except' => ['login','signup']]);
Better use create or save Method to store the new user. After you store user in your database you can generate a usertoken and send him back. And the user is logged in. Every further request is then regulated via the token.
$token = // generate an new token with the JWT toker Helper method ;
return response()->json([
'status' => 'ok',
'token' => $token,
'user' => $user
], 201);
Related
I created a Laravel App. It could access through web, for admin's web page, and api for user's page. I created user's page using Vue so it needs API.
Doing so, I need two Auth Controller. One is automatically created using laravel scaffolding, for the web. And the other is created manually for user's login via token.
I did create the AuthController for API. This is the controller.
<?php
namespace App\Http\Controllers\API;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use App\User;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
class AuthController extends Controller
{
//untuk login
public function login(Request $request)
{
//validasi data
$this->validate($request, [
'email' => 'email',
'username' => 'string',
'password' => 'required'
]);
//login dapat menggunakan email atau username
$user = User::where('email', '=', $request->email)
->orWhere('username', '=', $request->username)->first();
// $username = User::where('username', $request->username)->first();
// dd($username);
$status = "error";
$message = "";
$data = null;
$code = 401;
// echo (gettype($email));
// echo(gettype($username));
// echo($email);
if($user){
if (Hash::check($request->password, $user->password)){
$user->generateToken(); //generated 60 random string
$status = 'success';
$message = 'Login Success';
//tampilkan data user menggunakan method to Array
$data = $user->toArray();
$code = 200;
}
else{
$message = "Login gagal, password salah";
}
}
else {
$message = "Login gagal, username atau email salah";
}
return response()->json([
'status' => $status,
'message' => $message,
'data' => $data,
], $code);
}
//untuk registrasi
public function register(Request $request)
{
$validator = Validator::make($request->all(),
[
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6',
'username' => 'string'
]);
if ($validator->fails()){
$errors = $validator->errors();
return response()->json([
'data' => [
'message' => $errors,
]
],400);
}
else{
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
'username' => $request->username,
'roles' => json_encode(['CUSTOMER'])
]);
if ($user){
$user->generateToken();
$status = "success";
$message = "Register berhasil!";
$data = $user->toArray();
$code = 200;
}
else{
$message = "Register gagal";
}
return response()->json([
'status' => $status,
'message' => $message,
'data' => $data
], $code);
}
}
//untuk logout
public function logout(Request $request)
{
//get authenticated user data
$user = Auth::user();
if($user){
$user->api_token = null; //delete user's token
$user->save();
}
return response()->json([
'status' => 'success',
'message' => 'logout success,
'data' => null,
], 200);
}
}
Login and Register method is worked. But when i try to run Logout method, i get AuthenticationException. I tried to debug the $user variable at Logout method, it return null. So, that's why i get the error. My question is, how i solve it? Is it even possible to create two different authentication controller in laravel?
For clarity, this is my api.php
//Routing bersifat publik
Route::prefix('v1')->group(function (){
Route::post('login', 'API\AuthController#login');
Route::post('register', 'API\AuthController#register');
Route::get('books', 'API\ApiBookController#index');
Route::get('book/{id}', 'API\ApiBookController#view')
->where('id', '[0-9]+');
Route::resource('categories', 'API\ApiCategoryController')
->except(['create', 'update']);
//Routing bersifat private
Route::middleware('auth:api')->group(function (){
Route::post('logout', 'API\AuthController#logout');
});
});
Logout method response:
{
"status": "error",
"message": "Unauthenticated.",
"data": null,
"errors": {
"exception": "Illuminate\\Auth\\AuthenticationException",
"trace": [
"#0 D:\\xampp\\htdocs\\book-store\\vendor\\laravel\\framework\\src\\Illuminate\\Auth\\Middleware\\Authenticate.php(68): Illuminate\\Auth\\Middleware\\Authenticate->unauthenticated(Object(Illuminate\\Http\\Request), Array)"
]
}
}
Thank you for your time and consideration.
config\auth.php
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
],
*Note: default guard in config\auth.php is web so i can log in to the web.
Use auth guard..
$user=Auth::guard('api')->user();
you have to specific what user should be logout in your controller in the apiController
you should change
$user = Auth::user();
to
$user = Auth::guard('api')->user();;
then logout him.
I want to use JWT to login in my API but it always give me
error: "Unauthorized".
Before this, i already register the email and password of the user in my database before trying to login
here's my code :
class UserController extends Controller
{
public function __construct()
{
$this->middleware('auth:api', ['except' => 'login']);
}
public function login(Request $request) {
$validator = Validator::make($request->all(), [
'email' => 'required|email|max:255',
'password' => 'required|string|min:6|max:255',
]);
if($validator->fails()) {
return response()->json([
'status' => 'error',
'messages' => $validator->messages()
], 200);
}
if (! $token = auth()->attempt(['email' => $request->email, 'password' => $request->password])) {
return response()->json(['error' => 'Unauthorized'], 401);
}
return $this->respondWithToken($token);
}
protected function respondWithToken($token) {
return response()->json([
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => Auth::guard()->factory()->getTTL() * 60
]);
}
/**
* Get the guard to be used during authentication.
*
* #return \Illuminate\Contracts\Auth\Guard
*/
public function guard()
{
return Auth::guard('api');
}
here's my guard and default in config/auth.php :
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
],
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
here's my frontend using VueJs that does the login :
axios.post('http://localhost:8000/api/login', loginData)
.then(response => {
console.log(response)
})
.catch(error => {
commit('loginStop', error.response.data.error);
commit('updateAccessToken', null);
console.log(error.response);
})
here's my web.php :
Route::group(['prefix' => 'api'], function() {
Route::post('/register', 'UserController#register');
Route::post('/login', 'UserController#login');
});
Here's my output of php artisan route:list :
Based on the comments, you aren't hashing the password of the user that you inserted in the database.
But you have to do it as Auth::attempt checks if the provided password would match the hash stored in the database.
If you still want to register the user manually, you can hook up a tinker interactive shell with php artisan tinker command and then user Hash::make('yourpassword') to generate an hashed password using the setted Laravel's password hashing system (defaults to bcrypt).
Then you just have to copy the output string into your database. The login should finally work as the Auth guard now can check the user input agains a correct database user with a proper hashed password.
I had a totally different issue.
The auth()->attempt method was not comparing the password to my User model password for some reason.
After adding the following to my User model:
public function getAuthPassword() {
return $this->password;
}
Everything worked like a charm
The same problem to me, I solved by:
Use tinker to generate user credentials, email and password
content type in Headers: application/x-www-form-urlencoded
Auth middleware in laravel to authenticate users using my custom guard but everytime i call a route with that middleware I get the error that :
Route [login] not defined.
Right now, i am just trying to make sure that the middleware is being called.This is what i have done so far:
public function handle($request, Closure $next, $guard = null)
{
return "hi";
if (Auth::guard('api')->guest()) {
if ($request->ajax() || $request->wantsJson()) {
return response('Unauthorized.', 401);
}
return redirect()->guest('hi/login');
}
return $next($request);
}
the above is the handle method for authenticate.php. this is my code for guard
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'access_token',
'provider' => 'users',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
],
The Routes:
This is the route group in which i have a sub-group that implements the auth
middleware
Route::group(['prefix' => 'app'], function() use ($router) { }
This is the route i am testing the middleware on Route::get('/subscribedcompanies','PromotionController#getFavoriteCompanies');
One more Thing i'd like to add is i'm trying to authenticate based on access_token from database. i have changed the authenticate and credentials function in login controller as follows:
protected function credentials(Request $request)
{
return array_merge($request->header('authorization'));
}
public function authenticate(Request $request)
{
$credentials = $request->header('authorization');
if (Auth::attempt($credentials)) {
// Authentication passed...
return redirect()->intended('/');
}
}
just give name to your login route as login
Route::post('/login', 'LoginController#index')->name('login');
I am trying to use JWT for laravel web page instead of session. so I made some changes.
Installed jwt-auth and configure
Then changed default guard as api in config/auth.php
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
'guards' => [
...
'api' => [
'driver' => 'token',
'provider' => 'users',
],
],
Now I am getting error
(1/1) FatalErrorException Call to undefined method
Illuminate\Auth\TokenGuard::attempt() in AuthenticatesUsers.php (line
75)
How to fix this and start token authentication for laravel web page(blades not API).
I'm also using jwt protecting our api. You should change your config like below:
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
'guards' => [
...
'api' => [
'driver' => 'jwt', // KEY POINT!!!
'provider' => 'users',
],
],
Make sure the jwt library installed correctly:
Tymon\JWTAuth\Providers\LaravelServiceProvider::class is added in your config/app.php.
Your user model implements JWTSubject interface if you use eloquent model in your provider.
I found the solution here : https://github.com/tymondesigns/jwt-auth/issues/860
In /routes/api.php - added a few basic authentication routes
Route::post('login', 'Auth\LoginController#login');
Route::get('/user', function (Request $request) {
$user = $request->user();
return dd($user);
})->middleware('auth:api');
In /app/http/Controller/auth/LoginController.php
and then override methods in login contoller
public function login(Request $request)
{
$credentials = $request->only(["email","password"]);
if ($token = $this->guard()->attempt($credentials)) {
return $this->sendLoginResponse($request, $token);
}
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
protected function sendLoginResponse(Request $request, $token)
{
$this->clearLoginAttempts($request);
return $this->authenticated($request, $this->guard()->user(), $token);
}
protected function authenticated(Request $request, $user, $token)
{
setcookie("jwt_token", $token);
return redirect('/');
return response()->json([
'token' => $token,
]);
}
protected function sendFailedLoginResponse(Request $request)
{
return response()->json([
'message' => "not found",
], 401);
}
Adding middleware AddToken
public function handle($request, Closure $next)
{
$token = isset($_COOKIE["jwt_token"])?$_COOKIE["jwt_token"]:"";
//$request['token'] = $token;//this is working
$request->headers->set("Authorization", "Bearer $token");//this is working
$response = $next($request);
//$response->header('header name', 'header value');
return $response;
}
Register middleware in Kernel.php
protected $middleware = [
....
\App\Http\Middleware\AddToken::class,
];
I think you can try this :
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
EDIT
You can find some help from the step by step example. In this example you need to focus on how to configure and use that token base authentication.
Hope this help you well.
Please refer this link. If you are using api as default then laravel authentication will throw an error.
Laravel uses default Session based authentication out of the box with the default scaffolding users-view-controller that you already have. You have additional means of adding your own custom guard in the doc, so you can make use of the guard as needed.
Therefore as #KevinPatel suggested, revert back to the default configuration, then in your route: group the route you want to be under JWT authentication, add the JWTMiddleware, in this case you have to update the controller responsible for your authentication to use the JWTAuth instead of the default auth.
You should check this answer if you need to understand it better check this answer on Laracasts
One recommended way to incorporate the JWTAuth is to go for Dingo API (of course you are not building api, but) because Dingo already added some flesh to the authentication and other routes management - so things are pretty easy to use and configure
I've created code and authenticated user using guard but it doesn't provides me a api_token
/**
* This'll provide login authentication to the user
* #param Request $request
* #return json
*/
public function authenticate(Request $request)
{
//getting and setting locale for the request
$locale = ($request->header('lang-code') == 'KO') ? "ko" : "en";
app()->setLocale($locale);
$credentials = $request->only('email','password');
try {
// verify the credentials and create a token for the user
if (!$token = auth()->attempt($credentials)) {
return response()->json(['success' => parent::FAILURE, 'message' => trans('messages.api.login.failure')],401);
}
} catch (GeneralException $e) {
// something went wrong
return response()->json(['success' => parent::FAILURE, 'message' => trans('messages.api.login.tokenNC')],500);
}
return response()->json(['success' => parent::SUCCESS, 'message' => trans('messages.api.login.success'), 'data' => auth()->user()],200);
}
Above function is working fine but I'm not getting token when I use auth()->guard('api')->user()->api_token. This column is already within my DB even though I'm not able to generate api_token what can be the issue over here.
EDITED
routes/api.php:
Route::group(['namespace' => "Api\\v1", 'as' => 'api.v1.', 'prefix' => 'v1'], function () {
Route::any('/login', 'AccessController#authenticate');
});
config/auth.php:
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
],
You may need to make sure that any routes that will be using Token Authentication are being protected by the auth:api middleware.
Like this example :
Route::group(['prefix' => 'api/v1', 'middleware' => 'auth:api'], function () {
Route::post('/authentificate', 'AuthController#authentificate');
});
You can use model mutators to do that automatically or override the boot method of your Model Class which is in your case User Model
protected static function boot()
{
parent::boot();
static::creating(function($model)
{
$model->api_token = $model->generateCode();
});
}
protected function generateCode()
{
return bin2hex(openssl_random_pseudo_bytes(16));
//you can use your own random fucntion here or you can use inbuilt Crypt funciton
}