JWT refresh token [Laravel 5.2] - laravel-5

I am using Tymon pkg for JWT auth in Laravel 5.2
In my Kernel I have middlware:
'jwt.refresh' => \Tymon\JWTAuth\Middleware\RefreshToken::class,
Anyone can explain me how to use it and how to set up refresh token in my app server side?

You can use refresh token middleware in routes or route groups.
Route::group([
'prefix' => 'api',
'namespace' => 'API',
'middleware' => ['throttle', 'jwt', 'refresh'],
], function(){
// Yor routes logic...
});
Please read more about refreshing token and review jwt.php config file for more details on refreshing tokens.

Related

Laravel API response Unauthenticated even when Authentication is passed

I am using the jwt for creating the tokens while login. After I login, I try to hit the /me api pointing to the function:
public function me()
{
$user = auth()->user();
return response()->json($user);
}
I followed the JWT official documentation, initially I was able to get the response for the API. Suddenly it started throwing a
{
"message": "Unauthenticated."
}
Why is this happening?? Is there any workaround? It would be great if someone could help.
i tried documentation setup and worked fine, you might missed passing authentication header in your api call. since idk what's your setup i can only tell when you logged in, you should use received token in api calls with authentication.
PostMan Software: In headers tab add a key as Authorization and assign token for value with Bearer, like Breaer token......
for more help please clarify how you're trying api calls.
Edit: added an alternate way for using middleware
Another way of implementing or using middleware :
Create a Middleware with JWT name and put below code in handle function
Don't forget to import
use JWAuth;
public function handle($request, Closure $next)
{
JWTAuth::parseToken()->authenticate();
return $next($request);
}
Then in Kernel add jwt to $routeMiddleware like this :
protected $routeMiddleware = [
// you should add below code.
'jwt' => \App\Http\Middleware\JWT::class,
];
in routes/api
Route::apiResource('/posts', 'PostController');
now in PostController add your middleware to Constructor like this.
public function __construct()
{
$this->middleware('jwt', ['except' => ['index','show']]);
}
So in construct you will set your middleware base on JWT, then with except you can modify which one of your functions don't need to authentication base on JWT token. now when you use auth()->user() you can get your info or etc.
So if i had index, show, update, delete, store, create when i try to do API call if i use GET METHOD for url.com/posts or url.com/posts/23 i can get my posts without passing JWT token.
When you tried to use JWT you should realize that it's working base on token you're passing, you're getting token when you using login, but you're not getting user info because you're not passing user's token to app, before all of this you should consider to verify token then do the rest Logics. Good Luck.
Edit : added more info
auth.php
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
],

Auth::user(); doesn't returns users, using passport

I have situation about returning users from DB. In my controller I am trying it like below:
UPDATED:
NOTE: for clear misunderstanding. Actually I am logged in as a user. No problem with that part. But it looks like auth:: doesn't understand that and when I try to retrieve users. it's redirecting me to login's endpoint...
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Auth;
class UsersController extends Controller
{
public function getUser(){
$users = Auth::user();
dd($users);
}
}
And about the api route:
Route::group(['middleware' => 'auth:api'], function() {
Route::post("logout", "Api\AuthController#logout");
/* User */
Route::get('/user', 'Api\UsersController#getUser');
});
Route::group(["prefix" => "v1"], function(){
/* Auth */
Route::post("login", "Api\AuthController#login")->name("login");
Route::post("register", "Api\AuthController#register");
});
Here is the thing. If I use my UserController route outside the middleware:api then endpoint is returns null. And if use it inside the middleware it redirects me to my login's endpoint. Because of the "->name('login')"
In the end I can't return the users. Additionally this is what config/auth looks like.
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
By the way before asked. I tried to change guard's web to api but nothing is changed.
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],
Is there anyone have better understanding on this situation. How can I return users with using passport? Do I missing something here?
Apparently, the problem is with the request header. Only a logged in user can call /api/user endpoint with an access_token in the request header.
Request header will have this pair
Authorization: Bearer eyJ0eXAiOiJKV1..........
Nothing to do in laravel part, as it's working as expected.
If you are using Laravel Passport. Let's read and make your step same in document: https://laravel.com/docs/5.8/passport
From your API request, need to pass the access_token to backend.
Hoping you can resolve that issue!

Laravel passport public api routes

I am trying to code a login function for my api that takes a username and password then give you a password grant token to make api requests. The login route when called gives you
{
"message": "Unauthenticated."
}
I am using passport on laravel to do secure the api. Why am I getting a 401 when the route does not have the auth:api middleware? I tried using a clousure to see if I get could get a response and the closure did not give me an error.
Route::group(['prefix' => '/v1', 'middleware' => ['auth:api'], 'namespace' => 'Api\V1', 'as' => 'api.'], function () {
Route::post('/post/like','PostLikeController#store');
});
Route::group(['prefix' => '/v1', 'namespace' => 'Api\V1', 'as' => 'api.'], function () {
Route::post('login', 'Auth\LoginController#login');
});
Does your login controller have a constructor? sometimes middleware is set in there?
Otherwise I've also had issues with having the middleware routes above the public ones.
Try putting the public routes in the file first and also checking the LoginController.php for a constructor which might be setting a middleware
It possibly due to the same prefixes, as it does not overriding but instead stacking on top of each other.
I suggest for your login route, possibly, you can use this
Route::post('login', 'Auth\LoginController#login')->withoutMiddleware([FooMiddleware::class]);
If it's still does not help try putting your login route above the middlewared route.

Token-based Authentication Laravel 5.5

Out of the gate, the auth config for Laravel specifies a token-based authentication approach for users:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
],
I have a few ajax endpoints I want to secure so no one outside of my application can interact with them. I've looked at Passport but it seems I may not actually need it given this auth configuration. How can I utilize this token to secure my ajax endpoints and if possible, identify the user the request belongs to?
Currently my api.php route file looks like:
//Route::middleware('auth:api')->group(function () {
Route::post('subscribe', 'SubscriptionController#create');
Route::post('unsubscribe', 'SubscriptionController#delete');
//});
I thought Laravel might've handled auth or something out of the gate for VueJS implementation but it doesn't look like it. My ajax request looks like:
this.$http.post('/api/subscribe', {
subscribed_by: currentUser,
game_id: this.gameId,
guild_discord_id: this.guildDiscordId,
channel_id: newChannelId,
interests: this.interests.split(',')
}).then(response => {
// success
}, response => {
console.error('Failed to subscribe');
});
As Maraboc already said, you should start by creating a column api_token: $table->string('api_token', 60)->unique(); in your users table.
Make sure each newly created user gets a token assigned, and encrypt it: $user->api_token = encrypt(str_random(60));
Next, you could define a Javascript variable in the footer of your app:
window.Laravel = <?php echo json_encode([
'apiToken' => !empty(Auth::user()) ? decrypt(Auth::user()->api_token) : ''
]); ?>;
Later, when you want to make a request to an endpoint, you should add a header, authorizing the user:
let url = '/path/to/your-endpoint.json';
let data = {
headers: {
'Authorization': 'Bearer ' + Laravel.apiToken
}
};
axios.get(url, data)
.then(response => console.dir(response));
Finally, in your controller, you can get your User instance by using Laravel's guard:
$user = !empty(Auth::guard('api')->user()) ? Auth::guard('api')->user() : null;
Hope this helps! BTW: these articles helped me on my way:
https://gistlog.co/JacobBennett/090369fbab0b31130b51
https://pineco.de/laravel-api-auth-with-tokens/
The solution I took was to not put ajax endpoints in the api namespace. By putting them as web routes instead of api it'll use CSRF (cross-site request forgery) protection to validate the route. So only if it comes from my domain will it be authenticated. This is ONLY useful when the site is served in https.

TokenGuard class always need api_token

I am using AngularJs and Laravel 5.4
In the default guard, I changed the web guard to api. Finally it looks like below.
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
when i send the request using username and password from Angular Js....I always get invalid credentials because..
TokenGuard class has a method called validate which expects api_token value but I am on the login page.
I am assuming that in order to get the token, I need $this->guard(web) in login method?
Is it correct approach or Am I missing something?
By default all routes defined in routes/api.php have the api middleware as defined in app/Providers/RouteServiceProvider::mapApiRoutes(). Therefore, you always need to pass api_token.
What you can do is, in your api routes, define the login route like this
Route::post('login', 'api\AuthController#login'); //out of the group
And post from AngularJS
$http.post({
url: 'http://localhost/api/login',
data: $scope.userda,
headers: {
Authorization: ''
}
}).then(...)
Then define all your other routes in a group with auth:api
Route::group(['middleware' => 'auth:api'], function(){
//Other routes here
});
In angular, set the Authorization headers with the value of api_token. So before login, it will be empty and after login it will have the value of the user api_token.

Resources