all. I'm just trying to implement Single sign-on server using Laravel and passport app.
What I'm trying to achieve: A single sign-on server who listen to the request from the client and provide the authentication based on the requested parameter.
What I've achieved so far: The SSO server who listen to the client request and provide the authentication and redirect back to the client site only if the user already registered on the SSO server.
The problem is coming to the picture when the user is not registered on SSO server and try to register the account In this case Laravel register user and redirect back to the homepage instead client callback URL.
Please let me know if this is achievable in Laravel or someone does something special for it.
It is pretty much achievable, depends on how much effort you want to put towards it.
When the user is registering, you can save the callback URL in the session.
session(['callback' => $callback]);
Upon registration, redirect the user to their callback URL
return redirect()->away(session('callback'));
If you are still using the default Auth/RegisterController provided by laravel, you can change the redirect behavior by defining a custom redirect function
protected function redirectTo()
{
return redirect()->away(session('callback'));
}
Laravel will automatically pick it up.
Don't forget to delete the property
protected $redirectTo = '/home';
Yes you can do this with some customization in default registration functionality, you have to replace some code in RegistrationController as provided below:
app\Http\Controllers\Auth\RegistrationController
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use AuthenticatesUsers, RegistersUsers {
AuthenticatesUsers::redirectPath insteadof RegistersUsers;
AuthenticatesUsers::guard insteadof RegistersUsers;
}
public function register(Request $request)
{
$this->validator($request->all())->validate();
event(new Registered($user = $this->create($request->all())));
if ($this->attemptLogin($request)) {
if ($request->hasSession()) {
$request->session()->put('auth.password_confirmed_at', time());
}
return $this->sendLoginResponse($request);
}
}
Related
I am looking for some clarification as for how exactly to proceed with Oauth auth code PKCE grant when it comes to authorizing my own SPA.
So I get this when I am redirected from my SPA to backend (after I log in of course):
Now I get this, makes sense if I want to login into my app with google or twitter for example.
But If I want to log in to the backend app to get the token with my SPA - is there a way to avoid that every time a user logs in? Does it make sense?
I would like to have it from user perspective like this:
click login
redirect to backend pretending to be SPA (visually)
login
go straight back to SPA without having to confirm that stuff
I just mainly want to understand the process for SPA. I assume and suspect that what I want is simply not possible?
Yes you can :)
Create your own Passport client.
<?php
declare(strict_types=1);
namespace App\Models;
class PassportClient extends \Laravel\Passport\Client
{
/**
* Determine if the client should skip the authorization prompt.
*
* #return bool
*/
public function skipsAuthorization()
{
// todo: add some checks, e.g. $this->name === 'spa-client'
return true;
}
}
And update your App\Providers\AuthServiceProvider.
public function boot()
{
// ...
Passport::useClientModel(PassportClient::class);
}
I'm working on a project with laravel. in my project there's two type of users one of them are admins and other one is normal users.
btw project is only provides API and there's no blade views.
I give a token to any user or admin logins with the api. and application will identify user or admin by sending that token with an authorization header and I check if token is validate and the user type is admin then give access to the admin features for that client.
here's my code for this part:
$admin = Auth::guard('admin-api')->user();
if ($admin) {
// allow to use admin features
}
else {
return response()->json(['error' => 'token is invalid'], 401);
}
I read something about applying Restrictions on a controller class in laravel and it was written there to add a constructor like this into controller class:
public function __construct() {
$this->middleware('admin-api');
}
and also there's something like that just for Restricting routes. like this
but I just want to know is it necessary to add same constructor to my controller class while the project just provides API? or the way that I'm doing is correct?
You are doing it right.
I would prefer restricting the request via routes, so there is no need to add constructor on each new Controllers.
Route::middleware(['admin-api'])
->group(function () {
Route::get('cart', 'Carts\CartController#retreive');
Route::post('cart/coupon', 'Carts\CartCouponController#addCoupon');
Route::delete('cart/coupon', 'Carts\CartCouponController#deleteCoupon');
Route::delete('cart/flyer', 'Carts\CartController#deleteFlyer');
});
This will apply the admin-api middleware on all the routes in the group and there is no need to add a constructor on Carts\CartController and Carts\CartCouponController, just to have middleware restriction.
After following the installation for enabling the new built-in email verification, all is working good (sending email after registration and clicking the activation enable the account).
But, I'm faced with the case where the user must be logged-in in order for the verification process to engage. Meaning, if the user is not logged in prior to use the verification link, he will be redirected to the login page and then be presented the /resources/view/auth/verify.blade.php page.
I am reaching out to the community to see if this it intentional, a bug or something I'm doing wrong? Did someone run in the same situation?
The site I'm setting up have public access to most pages, but restricted to some (for now the user portal). I set up the routes/web.php as follow:
// Authentication
Auth::routes(['verify' => true]);
Route::group(['middleware' => ['auth', 'verified'], 'as' => 'portal.', 'prefix' => '/portal'], function () {
Route::get('/', 'PortalController#index');
Route::get('/profile', 'PortalController#index')->name('profile');
Route::get('/orders', 'PortalController#index')->name('orders');
});
By tracing the verification process, I was able to find out the process is forcing a log-in in the VerificationController constructor via the middleware shown below.
public function __construct()
{
$this->middleware('auth');
$this->middleware('signed')->only('verify');
$this->middleware('throttle:6,1')->only('verify', 'resend');
}
By commenting the first line or adding ->except('verify'), the log-in page is not shown but an error is thrown at the Traits VerifiesEmails method Verify like below, since the user is obviously not logged it (the $request->user() is null).
public function verify(Request $request)
{
if ($request->route('id') == $request->user()->getKey() &&
$request->user()->markEmailAsVerified()) {
event(new Verified($request->user()));
}
return redirect($this->redirectPath())->with('verified', true);
}
My question, is there a way to get it to work without being loged-in beforehand, or is this the way the Verification process is implemented in 5.7? ... or what am I doing wrong?
is there a way to get it to work without being loged-in beforehand, or
is this the way the Verification process is implemented in 5.7? ... or
what am I doing wrong?
This is the way the Verification process is implemented in Laravel 5.7. Laravel uses signed URLs for verification. The URL is generated with an id parameter (id as user ID) and when the user clicks on the verification link, 3 checks are done:
Is the signature valid? (signed middleware)
What's the user ID in the signature? That's the ID that would ultimately be validated
Does the currently logged in user have the same ID?
You can always remove the third check by overriding the verify method in your VerificationController like so:
public function verify(Request $request)
{
$userId = $request->route('id');
$user = App\User::findOrFail($userId);
if ($user->markEmailAsVerified()) {
event(new Verified($user));
}
return redirect($this->redirectPath())->with('verified', true);
}
I have followed the steps of this tutorial in order to setup API authentication in Laravel 5.3 using the auth:api middleware.
Everything is working as expected apart from I am finding that in order to successfully access my API, I only need to provide an API token for any user in my users table rather than the token linked to the user currently logged in.
Is this expected behaviour because this middleware is stateless? I am using AdLdap2 to authenticate users but I can't see what I could be doing wrong especially as I have followed the steps in the tutorial above.
I have also had a look at TokenGuard which deals with API token validation but can't see any logic that ensures the token matches that of the user logged in.
Any help is much appreciated.
I think the authentication works like expected. The only thing auth:api does is making sure you are authenticated to access the protected routes. If you want to protect a specific route to only one user you could use Gates
So if you have a route to access a user like below and you want the user that's logged in to only access herself you can add a gate.
routes/web.php
Route::get('/user/{id}', function ($id) {
$userYourTryingToView = User::find($id);
if (Gate::allows('get-user', $userYourTryingToView)) {
// The user is allowed to access herself, return the user.
return response()->json($userYourTryingToView);
}
// User is not authenticated to view some other user.
return response('Unauthenticated', 403);
});
And in your app/Providers/AuthServiceProvider.php
/**
* Register any authentication / authorization services.
*
* #return void
*/
public function boot()
{
$this->registerPolicies();
Gate::define('get-user', function ($authenticatedUser, $userYourTryingToView) {
return $authenticatedUser->id == $userYourTryingToView->user_id;
});
}
For some reason I have had a mind block and can't figure out what is probably a very simple fix.
I have a Laravel 5 App and am using Zizaco's Entrust package for Access Control.
I want to protect a route so am using route Protection in routes.php as follows:
Entrust::routeNeedsRole('passtypes', array('admin'), null, false);
Which works as expected, apart from when a user's session has expired or they are not logged in and try to access the route.
In this case I would want Laravel's Authentication to be checked first, and redirect to the login page; however Entrust redirects to the 403 error first; which is confusing for a user that has ability to view that page, but is told they do not have access, rather than that they are not logged in/session has expired.
I initiate the Authentication in the Controller rather than in the route:
public function __construct()
{
$this->middleware('auth');
}
So just need to know how to get the same functionality, but by having auth get checked before the route permission requirement.
Thanks
I think that Entrust::routeNeedsRole fires before controller. Can you move Entrust to middleware? You could then check in middleware if user is logged in and then check if he has required role.
It's been a while, but I had a similar problem. The only difference, my entire app had to be protected. I ended up modifying Authenticate Middleware handle method:
public function handle($request, Closure $next)
{
if ($this->auth->guest()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
/**
* This is to protect the entire app, except login form,
* to avoid loop
*/
if($request->path() != 'auth/login')
return redirect()->guest('auth/login');
}
}
return $next($request);
}
And inside Kernel.php moved Authenticate from $routeMiddleware to $middleware
Then you can protect your routes with Entrust.