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', '.*');
Related
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
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);
}
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
showing {"error":"Unauthenticated."}, while calling larvel API in Laravel 5.4 and passport version: v1.0.9, using ajax call.
Calling from route api:
Route::get('category/get_tree_data', 'CategoryApiController#getTreeData')->middleware('auth:api');
If you set up Laravel Passport properly, you should have this in your view:
You need to create a client, that client has a client id and a client secret.
Now you need to open your consumer app which shall contain your client id and your client secret.
It looks like this(you have to change the token and id to your specific one):
class OAuthController extends Controller
{
public function redirect()
{
$query = http_build_query([
'client_id' => 3,
'redirect_uri' => 'http://localhost/app/public/callback',
'response_type' => 'code',
'scope' => '',
]);
return redirect('http://localhost/app/public/oauth/authorize?' . $query);
}
public function callback(Request $request)
{
$http = new Client;
$response = $http->post('http://localhost/app/public/oauth/token', [
'form_params' => [
'grant_type' => 'authorization_code',
'client_id' => 3, // from admin panel above
'client_secret' => 'BcTgzw6YiwWUaU8ShX4bMTqej9ccgoA4NU8a2U9j', // from admin panel above
'redirect_uri' => 'http://localhost/app/public/callback',
'code' => $request->code // Get code from the callback
]
]);
return json_decode((string) $response->getBody(), true);
}
}
Now you need to call that consumer app and authorize your application.
If that worked you get an access token + a refresh token.
It should look like this:
Now you can test this using a program like postman.
You basically call your get route and add the access token, which gives you access to the api, like this:
If you have any more question I recommend reading the docs.
Thus I highly recommend watching following video from Taylor Otwell.
Of course you can give me a comment aswell if you have any more questions.
Add this code inside your /resources/assets/js/bootstrap.js file
window.axios.defaults.headers.common = {
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
'X-Requested-With': 'XMLHttpRequest'
};
working perfectly...
I have the same issue with Laravel 5.8 when calling /api/user on auth:api middleware, I've tried to call the API url using Postman but got unauthenticated message
And I am able to fixed it by changing the hash value to false in config/auth.php file
// routes/api.php
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
// config/auth.php
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false, // <-- change this to false
],
],
I faced the same issue.
In my case, I was caching generated token after user login.
$token = $user->createToken('API'.'-'.strtoupper($user->username).'-'.'-X-AUTH-TOKEN', [$this->scope]);
Cache::add(strtoupper($user->username).'-'. 'X-TOKEN', $token->accessToken, $expiresAt);
After debugging, tried clearing cache
Cache::clear();
and it's working now.
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',
],
],