I am a beginner in Laravel. I have successfully generated a jwt token, and I want to send this token to another api which will authenticate it and sends the response of dishes. But my code is not validating the token, and gives me the response even if I send the wrong token.
How can I solve this?
Code:
class DishController extends Controller
{
public function self()
{
try{
$user = Auth->user();
$dishes = Dish::all();
}
catch(\Tymon\JWTAuth\Exceptions\UserNotDefinedException $e){
return response()->json(['error' => $e->getMessage()]);
}
return response()->json($dishes);
}
}
Api route
Route::get('/dish/self',[
'as' =>'login.login',
'uses' => 'DishController#self'
]);
in your route, you should gives a middleware (apiJwt), see below the code:
Route::middleware("apiJwt")->get('/dish/self',[
'as' =>'login.login',
'uses' => 'DishController#self'
])
something like this
remember, you should install some packages like the tymon/jwt-auth
Related
My laravel project has an API route by auth.basic middleware which is used id of the authenticated user in the controller. when I call it in postman it works well and I get 401 when the username or password is incorrect, but in laravel APITest which extends from DuskTestCase, authentication does not take place so I get 500 instead of 401 when the user's informations were incorrect. However, by correct information, I have the same error because auth() is null.
it is written like below, which is wrong?
api.php route:
Route::get('/xxxxxx/xxxxxx/xxxxxxx', 'xxxxx#xxxx')->middleware('auth.basic');
APITest:
$response = $this->withHeaders(['Authorization' => 'Basic '. base64_encode("{$username}:{$password}")])->get("/xxxxxx/xxxxxx/xxxxxxx");
You can use actingAs() method for authentication in tests.
An example from docs:
public function testApplication()
{
$user = factory(App\User::class)->create();
$this->actingAs($user)
->withSession(['foo' => 'bar'])
->visit('/')
->see('Hello, '.$user->name);
}
Another example that you can use for an API:
$user = User::factory()->create();
$response = $this->actingAs($user)->json('GET', $this->uri);
$response->assertOk();
For more information: https://laravel.com/docs/5.1/testing#sessions-and-authentication
I have an api that has a method to start and I am calling it from a frontend project.
In the front end project I use Guzzle to make the call via post to the api and login, from which I get back a json with the user data and a jwt token.
But when I receive the token as I manage the session, I must create a session and save the token, since the laravel to authenticate I need a model user and have a database, which of course I do not have in this backend because I call the api to log in, which brings a token and user data, then as I manage it from the backend, I'm a little lost there.
$api = new Api();
$response = $api->loginapi(['user'=>'wings#test.com','password'=>'123']);
Because here I could not do Auth::login($user) to generate the session.
Because I don't have here the database because the login is done from the api.
There I call the api, of which the answer is the token, but how do I manage it from here, creating a session? saving the token?
thanks for your help.
With api, you don't usually manage a session. usually, you'd call something like
Auth::attempt([
'email' => 'me#example.com',
'password' => 'myPassword'
]);
If the credentials are correct, laravel will include a Set-Cookie header in response, and, that is how you authenticate with api. Via an auth cookie. You don't need to do anything else.
Let's show you how:
//AuthController.php
public function login(Request $request) {
$validatedData = $request->validate([
'email' => 'required|email',
'password' => 'required'
]);
if(Auth::attempt($validatedData)){
return ['success' => 'true'];
}
else{
return ['success' => false, 'message' => 'Email or password Invalid'];
}
}
public function currentUser (){
return Auth::user();
}
Now, the APi file
Route::post('/login', ['App\Http\Controllers\AuthController', 'login']);
Route::get('/current_user', ['App\Http\Controllers\AuthController', 'currentUser']);
Now if you make a call to /api/current_user initially, you'll get null response since you're not currently logged in. But once you make request to /api/login and you get a successful response, you are now logged in. Now if you go to /api/current_user, you should see that you're already logged in.
Important ::
If you are using fetch, you need to include credentials if you're using something other than fetch, check out how to use credentials with that library or api
You want to use the API to authenticate and then use the SessionGuard to create session including the remember_me handling.
This is the default login controller endpoint for logging in. You don't want to change this, as it makes sure that user's do not have endless login attempts (protects for brut-force attacks) and redirects to your current location.
public function login(Request $request)
{
$this->validateLogin($request);
// 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.
if (method_exists($this, 'hasTooManyLoginAttempts') &&
$this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
if ($this->attemptLogin($request)) {
if ($request->hasSession()) {
$request->session()->put('auth.password_confirmed_at', time());
}
return $this->sendLoginResponse($request);
}
// 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.
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
The core happens when we try to "attemptLogin" at
protected function attemptLogin(Request $request)
{
return $this->guard()->attempt(
$this->credentials($request), $request->boolean('remember')
);
}
When using the SessioGurad (which is default) the method attemptLogin fires a couple of events, checks if the user has valid credentials (by hashing the password and matching it with db) and then logs the user in, including the remember me functionality.
Now, if you don't care about events, you can just check from your API if the credentials match and then use the login method from the guard. This will also handle the remember me functionality. Something like this:
protected function attemptLogin(Request $request)
{
$username = $request->input($this->username());
$password = $request->input('password');
$result = \Illuminate\Support\Facades\Http::post(env('YOUR_API_DOMAIN') . '/api/v0/login' , [
'username' => $username,
'password' => $password
])->json();
if(empty($result['success'])){
return false;
}
// Maybe you need to create the user here if the login is for the first time?
$user = User::where('username', '=', $username)->first();
$this->guard()->login(
$user, $request->boolean('remember')
);
return true;
}
I am using laravel passport but when I try to hit the post route that gives me user data it's giving me error like
{"message":"Unauthenticated."}
here is my controller method
public function getDetails()
{
$user = Auth::user();
return response()->json(['success' => $user], $this->successStatus);
}
api.php
Route::post('register', 'API\PassportController#register')-
>name('register');
Route::post('login', 'API\PassportController#login')->name('login');
//Route::post('details', 'API\PassportController#getDetails')->middleware('auth:api');
Route::group(['middleware' => 'auth:api'], function(){
Route::get('user', 'API\PassportController#user');
Route::post('details', 'API\PassportController#getDetails');
});
screenshot of postmen
please let me know what inputs you want from my side
Your codes look ok to me, but if I'm not mistaken you added your "Authorization" manually: please try this way from the image below, by clicking on Authorization tab, left next to Headers tab.
And make sure that your token is the one that is returned from the server when you make login request: see the image below.
Authentication is working, I have a few routes under auth middleware, Whenever i request it throws :
{
"message": "Failed to authenticate because of bad credentials or an invalid authorization header.",
"status_code": 401
}
How can i send the token with the request like :
Authorization bearer {{Long token}}
It works with `postman`, How can i send the token with request header, Or in any other best way.
Route :
$api->get('/categories', [
'uses' => 'App\Http\Controllers\CategoryController#index',
'as' => 'api.categories',
]);
Method :
public function index() {
$lessons = \App\Category::all();
$token = JWTAuth::getToken(); // $token have jwt token
return response()->json([
'data' => $lessons,
'code' => 200,
]);
}
The question was pretty vague to answer. Please be more specific from next time. From your comments i could finally realise that you want to consume the api from a mobile app.
You need to return the token generated for an user either during login or during registration or any other authentication method/route you have. The mobile app needs to read this response and store the token locally. Then the app needs to inject this token in the request header for every single request. That's the normal api token workflow.
The app should also be coded to read the error response from requests and if it returns errors for expired or invalid token, the app needs to clear the locally stored token and then request the user to login again to generate a fresh token.
you can use : https://github.com/tymondesigns/jwt-auth
requriment :
Laravel 4 or 5 (see compatibility table)
PHP 5.4 +
Steps:
1 : add below line in composer.json in require array
"tymon/jwt-auth": "0.5.*"
2 : run "composer update" in your terminal
3 : after this you have to register service provider
go to config/app.php
and add 'Tymon\JWTAuth\Providers\JWTAuthServiceProvider' this in provider array
and 'JWTAuth' => 'Tymon\JWTAuth\Facades\JWTAuth' , 'JWTFactory' => 'Tymon\JWTAuth\Facades\JWTFactory' this to aliases array
4 : publish pacakge :
"php artisan vendor:publis --provider="Tymon\JWTAuth\Providers\JWTAuthServiceProvider"
5 : generate secrate key in config file
'php artisan jwt:generate'
6 : for addition configuration : https://github.com/tymondesigns/jwt-auth/wiki/Configuration
Usage :
AuthenticateController.php
use JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;
class AuthenticateController extends Controller
{
public function authenticate(Request $request)
{
// grab credentials from the request
$credentials = $request->only('email', 'password');
try {
// attempt to verify the credentials and create a token for the user
if (! $token = JWTAuth::attempt($credentials)) {
return response()->json(['error' => 'invalid_credentials'], 401);
}
} catch (JWTException $e) {
// something went wrong whilst attempting to encode the token
return response()->json(['error' => 'could_not_create_token'], 500);
}
// all good so return the token
return response()->json(compact('token'));
}
}
You can also skip user authentication and just pass in a User object. e.g.
// grab some user
$user = User::first();
$token = JWTAuth::fromUser($user);
The above two methods also have a second parameter where you can pass an array of custom claims. e.g.
$customClaims = ['foo' => 'bar', 'baz' => 'bob'];
JWTAuth::attempt($credentials, $customClaims);
// or
JWTAuth::fromUser($user, $customClaims);
create token based on anything
$customClaims = ['foo' => 'bar', 'baz' => 'bob'];
$payload = JWTFactory::make($customClaims);
$token = JWTAuth::encode($payload);
d
I am using Laravel 5.1 and I am trying to setup a simple login/logout system. I can easily login using:
Auth::attempt(['email' => $request->email, 'password' => $request->password]);
But if I try to logout via an ajax request using Auth::logout();, it does not log out the user. Manually going to the logout route in a browser tab however works just fine.
note: if my controller looks like this:
public function logout()
{
Auth::logout();
dd(Auth::user());
}
Then the request returns null. This should indicate the user has been logged out, but if I pass another request - I am still logged in.
Edit
Ajax call:
import request from 'superagent'
request.get(env.api + endpoint)
.withCredentials()
.set({
'X-Requested-With': 'XMLHttpRequest'
})
.end((err, res) => {
if (err) return reject(err);
return resolve(res.body);
})
EDIT
I found the source of my problem. It was a single route that looked like this:
Route::get('image/users/{image}', ['as' => 'fetch.users.images', 'uses' => 'Files#fetchUserImage']);
Changing the route path image/users/{image} solved my problem. Still curious as to why this caused an error with Auth? The route was not interfering with any of my other routes.
Edit
My above edit was wrong. It is to do with that route but its not the naming.
I am requesting an image from the route Route::get('image/users/{image}', ['as' => 'fetch.users.images', 'uses' => 'Files#fetchUserImage']); whose associated controller looks like this:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Storage;
class Files extends Controller
{
public function __construct()
{
$this->middleware('basic');
}
public function fetchUserImage($image)
{
$image = 'users/images/' . $image;
if (Storage::disk('s3')->exists($image)) {
return response(Storage::disk('s3')->get($image), 200, ['Content-Type' => 'image/jpeg']);
} else {
return response('Image not found', 404);
}
}
}
I am requesting the image with JS like this:
let img = new Image();
img.onload = () => this.state.update ? this.setState({image: props.src}) : null;
img.src = this.props.src;
When Laravel returns 404 or false or anything that isn't an image, the JS sends the request again. After I logout, Laravel still has an image request to process and the response('Image not found', 404) gets triggered after my logout succeeds and then as the response contains the logged in session info, my browser gets indirectly logged back in.
Haven't come up with a fix for this yet. Not sure how to go about it.