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',
],
],
Related
I am trying to figure out to provide multiple ways of authentication for the API service within my Laravel app. The app is a SPA using Vue.js and uses the API route to render and present all the view components. Currently, I am using a JWT driver for the API guard within the application. However, I'd also like to offer my clients the ability to access the same API via OAuth and Laravel's personal API token. With that being said, how do I protect my resources with the Auth middleware where it can be accessed internally with a JWT or externally by a client with OAuth or an API Token.
Controller:
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
// Make sure user is authenticated
$this->middleware('auth:api');
//$this->middleware('auth:oauth');
}
Auth Guards:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
'oauth' => [
'driver' => 'token',
'provider' => 'users',
]
],
If you want to be able allow multiple guards for your routes you can supply the different guards to the middleware call, like you have done already with the api guard, except you supply them as comma separated values:
$this->middleware('auth:api,oauth,web');
This will mean that if a user has been authenticated with one of the guards they will be able to access the route(s).
Lets say I have the following guards:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'admin' => [
'driver' => 'session',
'provider' => 'users',
],
],
I login to my app as a normal user using the default 'web' guard and to access the authenticated user I can use the following: $user = Auth::user();
public function __construct()
{
$this->middleware('auth');
}
public function edit()
{
$user = Auth::user();
}
At the same time I also login to the same app as an admin using the 'admin' guard and in admin controllers I have the following middleware and to access the authenticated admin I do the following: Auth::guard('admin')->user()
public function __construct()
{
$this->middleware('auth:admin');
}
public function edit()
{
$user = Auth::guard('admin')->user();
}
The question is do I need to specify the guard each time to access the admin user - I've noticed once I've authenticated in constructor using $this->middleware('auth:admin') I no longer need to specify the guard to access the authenticated user inside other controller methods? Is this correct behaviour
As far as I can see, your admin guard isn't doing anything different to the web guard. It's using the same driver and the same provider. So there is absolutely no difference between using Auth::user() and Auth::guard('admin')->user().
If you do decide to implement a custom driver (different to the session driver) for your admin guard, you'll need to use Auth::guard('admin')->user() (or set your guard as default) when accessing the authenticated user. Otherwise, Auth::user() will look for user details in the session.
As a side note, the default session driver caches the user instance on first retrieval which in your case is when the request hits the auth middleware. Subsequent calls to Auth::user() or Auth::guard('admin')->user() are handled by returning the user instance from cache.
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!
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.
For two days I am digging google but could not find the starting thread for my problem, now I am out of option. Please help me with some direction/howTo
I have a web application running built with laravel 5.3, I have installed passport as described here . if I go /home its showing perfectly.
Now I have to make an android app from which
An already existing user of web app can login
get all the task list of that user TaskModel (ons_tasks(id, title, description))
routes related only
in web.php
Auth::routes();
in api.php
Route::get('/user', function (Request $request) {
return $request->user();
})->middleware('auth:api');
Route::group(['middleware' => ['auth:api']], function () {
Route::get('/test', function (Request $request) {
return response()->json(['name' => 'test']);
});
Route::get('/task/list', function (Request $request) {
$list = \App\Model\TaskModel::all();
return response()->json($list);
});
});
To login : if I send post request /login with email & password get the TokenMismatchException error but Where do I obtain a token for
android app in mobile? Do I need the Auth::routes() in the api too?
if then what else Do I need to just login and get a token so later I
can send it for getting the task lists.
Secondly,
If I go to /api/test it redirects me to /home page without
showing any error !!!
Thanks in advance.
To authenticate with your Passport-enabled API
You'll need to use the Password Grant Client in this situation, see this section of Passport's documentation.
Once you've generated a Password Grant Client, using:
php artisan passport:client --password
You will need to request an access token from your application, and send it with your subsequent requests, in order to access the protected auth:api middleware routes.
To get an access token, send a request to your app's /oauth/token route (this is a PHP implementation obviously, ensure you are correctly formatting below request in your Java implementation):
$http = new GuzzleHttp\Client;
$response = $http->post('http://your-app.com/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => '<client id returned from the artisan command above>',
' client_secret' => '<secret returned from artisan command above>',
'username' => 'taylor#laravel.com',
'password' => 'my-password',
'scope' => '',
],
]);
return json_decode((string) $response->getBody(), true);
Ensure you add the client_secret and client_id that was returned from the artisan call above, and ensure username and password references a valid user in your database.
If everything is fine here, you should receive an access_token and refresh_token in the response. The access_token is what you need to authenticate using the auth:api guard. To correctly pass this back to your api, you will need to send your subsequent requests with the headers Authorization: Bearer <your accessToken> and Accept: application/json
For example, to access your "test" route:
$response = $client->request('GET', '/api/test', [
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Bearer '. <accessToken from /oauth/token call>,
],
]);
If you've set these correctly, you should see a JSON response with the array you have specified.
Why is /api/test redirecting me with no error?
You are requesting a route with the auth:api middleware. This will redirect you as you have not specified the correct headers as described above, this is expected behavior.
Hope this helps.