Restrict API users sign in from Web Admin Portal - laravel

My Laravel application has an API(students) and a web portal(admins). students register via API. Admin users are generated by a super admin. They login via the admin portal. App\User model has been used to facilitate both types of users with the Spatie Laravel Roles and Permissions.
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
]
The problem is that the users who registered from the API can login via Web portal. But after login they cannot do anything because the web routes are having a role based middleware.
// web.php routes
Auth::routes(['register' => false]);
Route::group(['middleware' => ['role:admin']], function () {
Route::resource('classes', 'WEB\ClassController');
Route::resource('teachers', 'WEB\TeacherController');
});
// api.php routes
Route::post('register', 'API\RegisterController#register');
Route::post('login', 'API\LoginController#login');
Route::group(['middleware' => 'auth:sanctum'], function () {
Route::resource('papers', 'API\PaperController');
Route::resource('marks', 'API\MarkController');
});
What can I do to handle this situation?

You could either display a message after login to tell students you don't have the permission to access the resource, or you could put the middleware on your web login route, so they can't even access the login page and see a 401 error right away

Related

Is it possible to perform user authentication through Laravel Passport (not authorization)?

As I understand it, Passport is used to implement OAuth 2.0 standard support, and as I see it, OAuth 2.0 is an authorization technology and not authentication.
So before authorizing a user to do something, firstly I need to authenticate them. Is there a way for Passport to authenticate a user, or I should use some other means of user authentication? E.g I want to authenticate a user with login and password.
Edit:
I'm a little bit confused by the documentation. It's said:
Passport includes an authentication guard that will validate access tokens on incoming requests. Once you have configured the api guard to use the passport driver, you only need to specify the auth:api middleware on any routes that require a valid access token.
So it means that Passport utilizes guards not to authenticate users but to validate access tokens on routes where these tokens are required. Did I get that right?
Yes, you can use passport tokens for authentication. Make a token for a user and send it as response when a user login. Then apply that authentication to all the routes of that user using laravel guards.(Make sure your model extends Authenticatable and use HasApiTokens) An example for guardians is given below.
In auth.php do the following:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'guardians' => [
'driver' => 'passport',
'provider' => 'guardians',
'hash' => false,
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'guardians' => [
'driver' => 'eloquent',
'model' => App\Models\Guardian::class,
],
],
In AuthServiceProvider do this:
public function boot()
{
$this->registerPolicies();
//token will expire in one day
Passport::personalAccessTokensExpireIn(Carbon::now()->addDays(1));
Passport::routes();
}
Then in api.php do this to all the routes you want to authenticate.
Route::group(['middleware' => 'auth:guardians'], function () {
Route::post('/parent', [ParentController::class, 'parentsList'])
->name('parentsList');
});
Your controller code will be like:
$guardian = Guardian::where('email', $request->email)->first();
if (Hash::check($request->password, $guardian->password)) {
//passport package implement here...
$token = $guardian->createToken('Laravel Password Grant Client')->accessToken;
$data=['guardian'=> $guardian, 'token'=> $token];
return Response::json($data,200);
}
else {
$data=['error' => 'Mobile Number/Email or Password entered is incorrect.'];
return Response::json($data, 422);
}

auth:web fails to auhenticate where auth:api works, with the same code

I need to authenticate my web routes and I decided to use this middleware:
Route::group(['middleware' => ['auth:api']], function () {
Route::get('test', 'MainController#home');
Route::get('test1', 'MainController#home1');
});
I edited config/auth.php file to use my guard:
....
'guards' => [
'web' => [
'driver' => 'oauth2',
'provider' => 'users',
],
'api' => [
'driver' => 'oauth2',
'provider' => 'users',
'hash' => false,
],
],
...
I defined oauth2 in the AuthServiceProvider file like this:
Auth::extend('oauth2', function ($app, $name, array $config) {
// Return an instance of Illuminate\Contracts\Auth\Guard ...
return new OAuth2Guard(app(TokenUserProvider::class), $app->make('request'));
});
This code works well. The auth:api middleware is executed and the user is checked.
Now since I need the sessions I wanted to use auth:web middleware, with the same exact code. But If I use it the user is nomore authenticated and he is redirected to the login page.
I do not know why. Both web and api guards use the same driver.
Laravel provide separate file for API routes routes/api.php you can separate web and api routes routes. all API routes will be prefixed with "api". After separating routes just include 'web' middle-ware

Unauthenticated with the guard (session)

I don't need to use a token to authenticate but I am building a REST API. I made a custom guard to use the session with basic auth. When I try to authenticate from postman it always shows unauthenticated. When I try to login in 'php artisan tinker' with a 'user instance', it works. My questions are the following.
When I log in from Tinker using 'Auth::login($user)', does it keep
the session?
Why is the authentication not working from the code provided below?
Between API (api.php) and Web (web.php) routes which one is executed first?
When I use postman basic auth do I have to provide just a normal password like 'admin' or does it have to be a hashed password?
Auth.php
'api' => [
'driver' => 'session',
'provider' => 'users',
]
API Routes
Route::group(['prefix' => 'v1', 'middleware' => ['auth:admin', 'admin']], function () {
Route::get('/users/check', 'v1\UserController#userOnlineStatus');
Route::resource('/users', v1\UserController::class)->except([
'create', 'edit'
]);
});
Web Routes
Auth::routes();
Route::get('/{any}', 'SinglePageController#index')->where('any', '.*');

passport authentication not working in my Laravel 5.4 application?

I have configured passport authentication for my model 'Member'(members table).Access token created perfectly while login.But i could not authenticate after login apis.
i am getting below error
BadMethodCallException.Call to undefined method Illuminate\Database\Query\Builder::getAuthIdentifierName()
i thing you forgot to put auth:api middleware in routes.
please use authentication middleware like
Route::group(array('middleware' => ['auth:api']), function() {
//your routes;
});
Passport by default uses User model and here you are using Member table. Just check if you have included Model class inside the auth.php file inside config folder.
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Member::class,
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
Or try this https://github.com/santigarcor/laratrust/issues/134#issuecomment-300318982

Laravel oauth2 unauthorized redirect

I am trying to implement oath2 using laravel and passport. however i have managed to make everything up & running. But the problem i am facing is when token expires or without token the url redirects to the laravels login page. I was expecting an unauthorized error message with a status code 401.
oauth2 is implemented using passport. I think laravels default auth is creating the problem.
this is my code in routes
Route::group(['middleware' => 'auth:api'], function () {
Route::get('users', "\App\Http\Controllers\UserController#getUsers");
Route::post('permission/add', "\App\Http\Controllers\UserController#createPermission");
Route::get('permissions', "\App\Http\Controllers\UserController#getPermissions");
Route::get('permission/{param}', "\App\Http\Controllers\UserController#getPermission");
Route::post('role/add', "\App\Http\Controllers\UserController#createRole");
Route::get('roles', "\App\Http\Controllers\UserController#getRoles");
Route::get('user/profile', function () {
// Uses Auth Middleware
});
});
My output when unauthorized
my config/auth.php
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],

Resources