Laravel Passport custom validation for any /oauth/token request - laravel

I need to validate extra fields in my users table before i create the requested tokens, but i can't find a simple way to do it with Passport.
I find similar workarunds which returns a token using $user->createToken() but i can't find someone covering all default /oauth/token options like the refresh_token
Also i see Passport have some simple ways to customize the username column and the password validation but i think this not cover my neededs.
Update
Im not sure if this is the best solution but in Laravel 5.8 the passport package have this validateForPassportPasswordGrant() function which allow you to add some extra conditionals before allowing the authentication process to get completed.
class User extends Authenticatable
{
public function validateForPassportPasswordGrant($password)
{
if ($this->active != true) {
throw OAuthServerException::accessDenied('The account is not active');
}
return Hash::check($password, $this->password);
}
}

In your login method
if (Auth::attempt(['email' => $request->email, 'password' => $request->password, 'is_active' => 1, 'username' => $request->username])) {
// create a token here
}

Related

Create session on consuming login with api on laravel

I have an api that has a method to start and I am calling it from a frontend project.
In the front end project I use Guzzle to make the call via post to the api and login, from which I get back a json with the user data and a jwt token.
But when I receive the token as I manage the session, I must create a session and save the token, since the laravel to authenticate I need a model user and have a database, which of course I do not have in this backend because I call the api to log in, which brings a token and user data, then as I manage it from the backend, I'm a little lost there.
$api = new Api();
$response = $api->loginapi(['user'=>'wings#test.com','password'=>'123']);
Because here I could not do Auth::login($user) to generate the session.
Because I don't have here the database because the login is done from the api.
There I call the api, of which the answer is the token, but how do I manage it from here, creating a session? saving the token?
thanks for your help.
With api, you don't usually manage a session. usually, you'd call something like
Auth::attempt([
'email' => 'me#example.com',
'password' => 'myPassword'
]);
If the credentials are correct, laravel will include a Set-Cookie header in response, and, that is how you authenticate with api. Via an auth cookie. You don't need to do anything else.
Let's show you how:
//AuthController.php
public function login(Request $request) {
$validatedData = $request->validate([
'email' => 'required|email',
'password' => 'required'
]);
if(Auth::attempt($validatedData)){
return ['success' => 'true'];
}
else{
return ['success' => false, 'message' => 'Email or password Invalid'];
}
}
public function currentUser (){
return Auth::user();
}
Now, the APi file
Route::post('/login', ['App\Http\Controllers\AuthController', 'login']);
Route::get('/current_user', ['App\Http\Controllers\AuthController', 'currentUser']);
Now if you make a call to /api/current_user initially, you'll get null response since you're not currently logged in. But once you make request to /api/login and you get a successful response, you are now logged in. Now if you go to /api/current_user, you should see that you're already logged in.
Important ::
If you are using fetch, you need to include credentials if you're using something other than fetch, check out how to use credentials with that library or api
You want to use the API to authenticate and then use the SessionGuard to create session including the remember_me handling.
This is the default login controller endpoint for logging in. You don't want to change this, as it makes sure that user's do not have endless login attempts (protects for brut-force attacks) and redirects to your current location.
public function login(Request $request)
{
$this->validateLogin($request);
// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
if (method_exists($this, 'hasTooManyLoginAttempts') &&
$this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
if ($this->attemptLogin($request)) {
if ($request->hasSession()) {
$request->session()->put('auth.password_confirmed_at', time());
}
return $this->sendLoginResponse($request);
}
// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
The core happens when we try to "attemptLogin" at
protected function attemptLogin(Request $request)
{
return $this->guard()->attempt(
$this->credentials($request), $request->boolean('remember')
);
}
When using the SessioGurad (which is default) the method attemptLogin fires a couple of events, checks if the user has valid credentials (by hashing the password and matching it with db) and then logs the user in, including the remember me functionality.
Now, if you don't care about events, you can just check from your API if the credentials match and then use the login method from the guard. This will also handle the remember me functionality. Something like this:
protected function attemptLogin(Request $request)
{
$username = $request->input($this->username());
$password = $request->input('password');
$result = \Illuminate\Support\Facades\Http::post(env('YOUR_API_DOMAIN') . '/api/v0/login' , [
'username' => $username,
'password' => $password
])->json();
if(empty($result['success'])){
return false;
}
// Maybe you need to create the user here if the login is for the first time?
$user = User::where('username', '=', $username)->first();
$this->guard()->login(
$user, $request->boolean('remember')
);
return true;
}

How to create a client for Authorization Code Grant with PKCE in Laravel Passport?

I'm trying to implement the **Authorization Code Grant with PKCE ** flow in Laravel Passport. Its documentation says that I have to use this command:
php artisan passport:client --public
That's fine, but I have to do it manually, I want to create those clients automatically, I mean, bring to my users a dashboard where they can create their clients. For that, I need to call through Ajax (or fetch) from my frontend some endpoint of Laravel Passport who allows me to create PKCE clients, but I don't know which endpoint call.
Laravel Passport provides the POST /oauth/clients endpoint to create clients, but this only create Authorization Code Grant Clients (without PKCE) and I don't know how to specify to create a PKCE client (same problem for Password Grant Tokens clients).
I was searching in the Laravel Passport's Client Controller and I realized that I can't specify what kind of client I want, this is the store method of Laravel Passport's Client Controller:
public function store(Request $request) {
$this->validation->make($request->all(), [
'name' => 'required|max:191',
'redirect' => ['required', $this->redirectRule],
'confidential' => 'boolean',
])->validate();
$client = $this->clients->create(
$request->user()->getAuthIdentifier(), $request->name, $request->redirect,
null, false, false, (bool) $request->input('confidential', true)
);
if (Passport::$hashesClientSecrets) {
return ['plainSecret' => $client->plainSecret] + $client->toArray();
}
return $client->makeVisible('secret');
}
As you can see, in the create() method of the client, values are "hard-coded" preventing me to create another kind of client through the JSON API.
Also, I was searching in the Laravel Passport's Client Model and I realized that, with the model I can specify what kind of grants I want for that client:
protected $casts = [
'grant_types' => 'array',
'personal_access_client' => 'bool',
'password_client' => 'bool',
'revoked' => 'bool',
];
So, there have to be a way to create clients for any type of grants (like PKCE), but I don't know how.
Should I override the Laravel Passport's Client Controller? How can I do it? I know that I can use the model to create my own clients in my own endpoint, but I want to keep the POST /oauth/clients route, so I would need to override the Laravel Passport's Client Controller, but I don't know how, can you help me, please?

How to change expiration date of access token Laravel Passport

I'm trying to change the expiration date of access token Laravel Passport.
Here's what I have tried:
AuthServiceProvider
public function boot(){
$this->registerPolicies();
Passport::routes();
Passport::tokensExpireIn(Carbon::now()->addDays(1));
Passport::refreshTokensExpireIn(Carbon::now()->addDays(2));
Passport::personalAccessTokensExpireIn(Carbon::now()->addMonths(1));
}
UserController
public function login() {
$credentials = [
'email' => request('email'),
'password' => request('password')
];
if (Auth::attempt($credentials)) {
$success['token'] = Auth::user()->createToken('MyApp')->accessToken;
$success['name'] = Auth::user()->name;
return response()->json(['success' => $success]);
}
return response()->json(['error' => 'Unauthorized'], 401);
}
But it didn't work. The expired date didn't change in the database at field expires_at, it's still one year by default.
I'm trying to do this, cause I want to make a redirect to login form when access token will get expired. How can I do it?
I'm also not sure what would happen with a refresh token, will it return another access token and the user will not need to authorizе?
You're creating a personal access token that belongs to user.
A personal access token has a default expiration date of 1 year.
Looking at your code I'm pretty sure that this command should do the work:
Passport::personalAccessTokensExpireIn(Carbon::now()->addMonths(1));
Double-check the expire_at column in the database and expires_in value in your response when you getting the token. It shows the number of seconds the token lives.

Pass user id in laravel after logged in

I would like to pass / submit the user_id of the currently logged on user. How will I do it in laravel 5.2? Please need help
I am not sure on my code on how will I use Auth:user() blah blah. Need help with this. I am new to this.
You can use the login functionality like this and pass the datas to the required pages as per your wish.
public function Dologin()
{
// create our user data for the authentication
$userdata = array(
'email' => Input::get('email'),
'password' => Input::get('password'),
);
if (Auth::attempt($userdata))
{
$user_id=Auth::user()->user_id;// user_id it will change as per the users table in your project.
return redirect('index');
}
else
{
}
}
Make sure you save your password using bcrypt method and for that alone the Auth::check() and Auth::user() will work.
auth()->id() will provide the user id

laravel 5.2 user login with active status

hi every one i am using laravel 5.2 default auth but i want that the user must only be logged in with active status.
https://laravel.com/docs/5.2/authentication
in this link they given the method like the following
if (Auth::attempt(['email' => $email, 'password' => $password, 'active' => 1])) {
// The user is active, not suspended, and exists.
}
but I did not find this where it is located in laravel 5.2.
I searched but the solutions are for previous versions and not for 5.2.
So please help me to login the users that has active status only so give me laravel 5.2 not of 5.1 or previous versions built in or custom solution to solve the problem
Assuming you are using the default auth setup, you can override the getCredentials method on the AuthController, which comes from the AuthenticatesUsers trait.
protected function getCredentials(Illuminate\Http\Request $request)
{
return $request->only($this->loginUsername(), 'password') + ['active' => 1];
}
That method returns the credentials array that is passed to Auth::attempt in the login method of AuthController. As other people have mentioned you will need to have a active field on your users table.
That example is only to show you can add custom fields when attempting to login.
You need to add an extra field to your User table like isActive.
When you have done this you can check if a user is active in your application.
if($user->isActive) {
// do something
}

Resources