Getting 401 in all Laravel api requests - php

I'm using Laravel with Passport to secure my API with OAuth.
Although, after using a authorized token got with PostMan tool, in all my request using the Passport middleware i'm getting 401.
I installed Laravel twice and looked all around the Internet without success and followed this page for installation: click here.
There is some of my codes:
The route i'm trying to access:
Route::group(['middleware' => 'auth:api'], function(){
Route::get('/user', function (Request $request) {
return $request->user();
});
});
The auth guard:
'guards' => [
//..
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],
Update 1: headers of request
Accept: application/json
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImU5ZDcwZGY0ZjA2MGZhNDk5MzQ1ZjQyN2QxMWY1MDhkZDI2ZWQxODkzZDgxMTcxYWNkZGYxYTkxYzkwNWYxOGUyMTI2NzY0M2QwZmQyOWRiIn0.eyJhdWQiOiIxIiwianRpIjoiZTlkNzBkZjRmMDYwZmE0OTkzNDVmNDI3ZDExZjUwOGRkMjZlZDE4OTNkODExNzFhY2RkZjFhOTFjOTA1ZjE4ZTIxMjY3NjQzZDBmZDI5ZGIiLCJpYXQiOjE1MDE1Mjc2NDYsIm5iZiI6MTUwMTUyNzY0NiwiZXhwIjoxNTMzMDYzNjQ2LCJzdWIiOiIxIiwic2NvcGVzIjpbXX0.dbJ4jddUZx1BT9X81LQIY-Dcx6xdDtmm2nH_C6t7rgFYzRTjab6w7T1NXfzKNlAeyi4iWJAARSBDI32vCeGuAy1ukFvr0qkoEp8UIZEqeeQYYam1Oox_0fuLlJyzwkOIospEc53KZBB0AQrPpW12abxZiZ6asQ9S4AbEJa5N95QFaYRMlxPxEMQOFt28v5148-shawcmtdV-AuAOpvsmap5_f4vQ-NY9R_He0NS4zOOQEY7sPIaRrsQ_XEAJwyiGnrUyufLr02T8wDUcqTskxCtizZx0aHN8i8lz9_X7xBFMHLj4zI4R3wfuZTWlOww07HdBt1oX8PAWvTgA0lw4Sq_xeKa3-MfuCasC4Vh_KWuvHQAfTIuCQw4lPOELfWWaeJTaEuuos7YFbOdoZIHoQWVs4lcisKpHuTGd8bzIPY9GGYsG26LRZB62vX358bijUuurh8p3ajPOt45tmvJnYyaHdf1gW5YwEqbtb07bohMrLFCNhYT0JFZvKa54FRRbB6BLA4lToDA4j1secMKan8mRMLwjEhqyPD0qxBswiMc127ryQ4CLvtKZ75Weno3oAnZ29ZkgtJCTESMzFjd41K-KgrV-s9KTWvfvmOECQUTQz6xUZ5WyVLzPZdBi6wNRYdAp4xRTA1RNUH3TSAP9qYt-xWTwNANXLvL5gBkBjQM
PS: the token is a Personal Access Token generated with Vue component.

when using postman did you force the Content-Type in your header like this
Content-Type: application/json

Try updating your route file this way:
Route::middleware(['auth:api'])->group(function () {
Route::get('/user', function (Request $request) {
return $request->user();
});
});
See more about routing here.

In version 5.6 and later of Laravel, cookies are no serialized/unserialized. However, Passport still expects that the cookies are serialized.
To fix this, you just need to add Passport::withoutCookieSerialization(); to app\Providers\AuthServiceProvider::boot()

Related

Unauthorized 401 error in laravel 6 passport

I'm trying to use the laravel passport to authenticate users. I followed every step in laravel passport documentation. But it shows error when I access a route that is protected by 'auth:api' middleware. I've searched over the internet but any of the answers are not working so far. Please see the code, and what I've tried so far below.
Tech used
Laravel 6
Laravel Passport
Vue 2
Axios
Tried so far:
Changed Passport::routes(); to Passport::routes(null, ['prefix' => 'api/oauth', 'middleware' => ['auth:api', 'web', 'auth']]); in AuthServiceProvider. Also tried Passport::routes(null, ['prefix' => 'api/oauth');
Tried to run php artisan cache:clear
routes/api.php
Route::middleware('auth:api')->group(function() {
Route::get('user', function() {
return request()->user();
});
Route::get('posts', 'PostController#index')->name('posts');
Route::post('posts/store', 'PostController#store')->name('posts.store');
Route::get('posts/{id}/show')->name('posts.show');
Route::get('users/{id}/show')->name('users.show');
});
Axios
mounted() {
axios.get('/api/posts')
.then(res => this.posts = res.data).catch(error => console.log('Unable to fetch posts.'))
}
Error
Headers:
Please let me know if you need some details that is not indicated on my post yet.
Setup
Run composer require laravel/passport:9 for the installation.
Run php artisan migrate for the tables.
Run php artisan passport:install to generate the encryption keys.
Added Laravel\Passport\HasApiTokens trait in User model.
Added Passport::routes(); in AuthServiceProvider.
Changed guard's api driver to passport in config/auth.php.
Full source code:
Click this link
I think you should review your code with the following steps.
Step 1: User model has to use HasApiTokens
...
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
}
Step 2: Passport::routes method within the boot method of your AuthServiceProvider
class AuthServiceProvider extends ServiceProvider
{
...
public function boot()
{
$this->registerPolicies();
Passport::routes();
}
}
Step 3: In your config/auth.php configuration file, you should set the driver option of the api authentication guard to passport
'guards' => [
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],
Step 4 (Optional):
If you want to consume your API from your JavaScript application, you need to manually send an access token to the application and pass it with each request to your application. However, Passport includes a middleware that can handle this for you. All you need to do is add the CreateFreshApiToken middleware to your web middleware group in your app/Http/Kernel.php file:
'web' => [
// Other middleware...
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
],
! You should ensure that the CreateFreshApiToken middleware is the last middleware listed in your middleware stack.
Edit (2021/10/17):
You should try to add the auth middleware to $middlewareGroups of your Kernel.php
protected $middlewareGroups = [
...
'api' => [
'throttle:60,1',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
'auth:api', //Need to add
],
];
Edit (2021/10/25):
I downloaded your code and debug it. When you debug it, you will get the following result:
Header JWT is not valid for JSON structure. There seems to be an incompatibility between the Laravel Passport library and your system. You should check your system version (PHP, Laravel, etc). I will continue to investigate. If you have any new information, please let me know
Edit (2021/11/02):
Update your laravel/framework dependency to ^6.0 in your composer.json file. If installed, update your laravel/passport dependency to ^9.3.2 in your composer.json file.
https://laravel.com/docs/6.x/upgrade#updating-dependencies
According to Laravel 6.x documentation, the version of Laravel Passport is from 9.3.2. Please try this version.
If you are using Api/oauth prefix AND add the auth:api middleware than you need to authenticate via Bearer tokens.
So it may be you have csrf token related issue so try below to disable it.
Passport::ignoreCsrfToken(true);
You should add token bearer into your ajax requests. You can get it after successful login.
// laravel
use Illuminate\Support\Facades\Auth;
use App\Models\User;
public function login()
{
$credentials = request(['email', 'password']);
$user = User::where('email', $credentials['email'])->first();
if (!$user || !$token = Auth::attempt($credentials)) {
return response()->json(['success'=> false, 'error' => 'неверный логин или пароль', 'cr' => $credentials], 422);
}
return $this->respondWithToken($token);
}
// vue login
async function login(email, password) {
try {
const response = await axios.post('/auth/login', {email, password});
const token = response.data.token;
// some func to store token, I am using vuex mutations for this
storeToken(token);
}
catch(error) {
console.error(error);
}
};
// vue regular function
async function changePassword(newPassword) {
// get token from global storage, with vuex it will be like store.state.auth.token
const token = getToken();
await axios.post('/user/changePassword', {newPassword}, headers: { Authorization: `Bearer ${token}`});
}
You've forgotten to run php artisan passport:keys ...so there may be no RSA key-pair available, which is crucial. Clients usually can be added with: php artisan passport:client. And generally speaking, there is no default recipe for debugging Laravel middleware ...there only is xdebug.

Laravel Passport Middleware "auth:api" Always Returns 401 with Valid Token

I am creating a Laravel API and want to secure it with Laravel Passport, however, it seems I can't get authenticated.
I began by securing my API routes using the Middleware auth:api inside my RouteServiceProvider.php
protected function mapApiRoutes()
{
Route::prefix('api')
->middleware('auth:api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
}
I also made sure to change the API driver in my config/auth.php to use passport
'api' => [
'driver' => 'passport',
'provider' => 'users',
'hash' => false,
],
I've then generated token using the methods recommended in the Laravel Docs. I did this inside of Postman.
I then used the Bearer token in the request Headers, along with the Accept and Content-Type being set to application/json (I've seen a lot on this issue in which people said this should be done)
And the Route in my api.php
Route::prefix('auth')->name('auth.')->group(function() {
Route::get('/user', function() { return response()->json(['error' => false, 'message' => 'Hello World']); })->name('user');
});
However, when I send the request I received the same 401 error given by Laravel Foundations Handler.php (I've edited the response to fit my use case but that has no affect on my current issue)
"messsage": "Unauthenticated."
Returning with the following headers;
While doing my research I found a question which described what I was experiencing but it seemed that it has been abandoned and no answer was provided. Any ideas?

Laravel OAuth token not working with Barryvdh\Cors and Passport

I'm working with laravel, using Cors and passport. Everything works great but authentication with the route ({{HOST/oauth/token}}) is not working always get
"Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource"
every other route is working perfectly. SO I just need to tell passport to use cors, I have tried this
In AuthServiceProvider
Passport::routes(null, ['middleware' => [\Barryvdh\Cors\HandleCors::class]]);
and this
Route::group(['middelware' => 'cors'], function () {
Passport::routes();
});
but nothing, login with oauth no working at all. Thank you in advance!!!
change the middleware statement to
Passport::routes(null, ['middleware' => [ \Barryvdh\Cors\HandleCors::class ]]);
refer to https://github.com/barryvdh/laravel-cors/issues/243

Laravel Passport: auth:api behaving like auth:web

I am trying to implement passport in my application to authenticate the api calls. I have done the configuration as mentioned in the official documentation.
I have this in my auth guard:
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
And, this in my AuthServiceProvider's boot() method:
Passport::routes();
And this is the route I am trying to access:
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
Route::group(['namespace' => 'Api', 'middleware' => 'auth:api'], function () {
// Login Controller
Route::get('/getclc', 'PreController#getClc');
});
I am sending the header in the request like this:
Authorization:Bearer $accessToken
My question is: 1. When a protected route is requested, it sends me to login page, but I want it to return the 401. How can I do that?
My laravel version is 5.4.33.
When authentication fails, Laravel throws an AuthenticationException exception. This exception is handled by your Laravel exception handler, and eventually calls the unauthenticated() method in your app/Exceptions/Handler.php file.
You can see from that method that if your request expects a json response, you'll get a 401 Unauthenticated response. However, if you're not expecting a json response, it just redirects to the route named "login". This will obviously fail if you don't have a route named "login".
Your request "expectsJson" when you send either the "X-Requested-With: XMLHttpRequest" header, or the "Accept: application/json" header. Otherwise, it is considered a normal web request.
If you'd like to change how your application handles unauthenticated users, the unauthenticated() method is the one to change.
Add this code on Headers on postman.
key Value
Accept application/json
Thanks

Laravel 5.3 API

When user enter username and password on the the browser and successfully logged in.
I like to make some API requests after user have logged in.
Laravel 5.3 provide api.php in routes folder.
in api.php I have included:
Route::group(['middleware' => ['auth']], function () {
Route::get('/test', function (Request $request) {
return response()->json(['name' => 'test']);
});
});
When requesting domain.com/api/test on the browser, for some reason it is redirecting to /home?
API token is not needed.
If you are specifying routes in api.php, you will need to use the auth:api middleware. So using your example it would be:
Route::group(['middleware' => ['auth:api']], function () {
Route::get('/test', function (Request $request) {
return response()->json(['name' => 'test']);
});
});
Notes about Token auth and Laravel 5.3:
If you've setup laravel's default auth system, you will also need to add a column for api_token to the user table. If you are using DB seeders, you might want to add something like:
$table->char('api_token', 60)->nullable();
to your users table seeder. Alternatively just add the column manually and fill that column with a random 60-char key.
When making the request, you can add the api_token as a URL/Querystring parameter like so:
domain.com/api/test?api_token=[your 60 char key].
You can also send the key as a header (if using Postman or similar), i.e:
Header: Authorization, Value: Bearer [your 60 char key].
I order to get a useful error if the token is incorrect, and not just be redirected to login, also send the following header with all requests:
Header: Accept, Value: application/json. This allows the expectsJson() check in the unauthenticated() function inside App/Exceptions/Handler.php to work correctly.
I found it hard to find clear docs from Laravel about using token auth with 5.3, I think it's because there's a drive to make use of Passport, and it supports tokens in a different way. Here's the article that probably helped most getting it working: https://gistlog.co/JacobBennett/090369fbab0b31130b51
first install the passport as stated here laravel passport installation
while consuming your own api add below line in your config/app.php in middleware section
'web' => [
// Other middleware...
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
],
now change your route to
Route::group(['middleware' => ['auth:api']], function () {
Route::get('/test', function (Request $request) {
return response()->json(['name' => 'test']);
});
});
now in your config/auth.php change these lines
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
The reason you are being redirected back to home is because the auth middleware checks if a user session is stored in your browser, but since api middleware does not make use of sessions (see app\http\kernel.php), your request is considered unauthenticated
If you would like to perform simple APIs that utilize sessions, feel free to add them in your web routes, and make sure to secure them by grouping them inside an auth middleware.
The standard behaviour in Laravel 5.5 is to delegate handling of authentication exceptions to app/Handler::unauthenticated(), in your project's application code. You'll find the code in there that redirects to the login page, and you can override it or perform further tests and contextualization in there. In previous versions of Laravel, 5.3 among them I believe, this exception handling was executed way down within the Laravel library within the vendor folder.

Categories