Trying to get property 'id' of non-object - php

If I try to log into my app with postman, I get an error on the indicated line:
Trying to get property 'id' of non-object
private $client;
public function __construct()
{
$this->client = Client::find(1);
}
public function login(Request $request)
{
$this->validate($request, [
'username' => 'required',
'password' => 'required'
]);
return $this->issueToken($request, 'password');
}
public function issueToken(Request $request, $grantType, $scope = "")
{
$params = [
'grant_type' => $grantType,
'client_id' => $this->client->id, // this line has error
'client_secret' => $this->client->secret,
'scope' => $scope
];
if($grantType !== 'social'){
$params['username'] = $request->username ?: $request->email;
}
$request->request->add($params);
$proxy = Request::create('oauth/token', 'POST');
return Route::dispatch($proxy);
}
Why am I getting this error message?
Note, on newer versions of PHP, this error will show as:
"Attempt to read property "id" on null

The error is because $this->client is null when find() cannot find the record.
You need to be sure if the record exists or not.
Change:
$this->client = Client::find(1);
To:
$this->client = Client::findOrFail(1);
Documentation:
From Laravel Eloquent docs,
this will throw a 404 error if no record with the specified id is found.

Make sure you have record in database table for User model with id = 1. When you're using User::find(1) Laravel tries to get this record from database, if record is absent this will return null

In your issueToken() method-
$client = Client::find(1);
if($client!=null){
$params = [
'grant_type' => $grantType,
'client_id' => $client->id,
'client_secret' => $client->secret,
'scope' => $scope
];
}else{
$params = [
'grant_type' => $grantType,
'client_id' => null,
'client_secret' => null,
'scope' => $scope
];
}

I had the same problem when I was trying access an id which doesn't exist in my project database. This $user= user::findOrFail($id); solved my problem.

Related

Laravel\Passport\Client returns null instance

My Auth API was working but now it gives error. I can register successfully but I cant get the return of the login token because I get an error:
TypeError: Argument 1 passed to App\Http\Controllers\UserController::getTokenAndRefreshToken() must be an instance of Laravel\Passport\Client, null given, called in /var/www/laravel/app/Http/Controllers/UserController.php on line 44 in file /var/www/laravel/app/Http/Controllers/UserController.php on line 47
Like I said, it was working before, I just added another model and created one-to-many relationship with user model but I don't think that has got anything to do with Passport.
Why I get a null object from OClient::where('password_client', 1)->first();
I create user like this in UserController's register method.
$user = User::create($input);
$oClient = OClient::where('password_client', 1)->first();
return $this->getTokenAndRefreshToken($oClient, $user->email, $password);
public function getTokenAndRefreshToken(OClient $oClient, $email, $password) {
$oClient = OClient::where('password_client', 1)->first();
$http = new Client;
$response = $http->request('POST', '/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => $oClient->id,
'client_secret' => $oClient->secret,
'username' => $email,
'password' => $password,
'scope' => '*',
],
]);
$result = json_decode((string) $response->getBody(), true);
return response()->json($result, $this->successStatus);
}

How can I change the default message of invalid credentials on OAuthServerException in Laravel Passport?

I am developing an API using Laravel Passport for authentication and my problem is that I cannot change the default message when the login fail due to invalid credentials.
LoginController.php
public function login(Request $request) {
$this->validate($request, [
'username' => 'required',
'password' => 'required'
]);
return $this->issueToken($request, 'password');
}
IssueTokenTrait.php
public function issueToken(Request $request, $grantType, $scope = "") {
$params = [
'grant_type' => $grantType,
'client_id' => $this->client->id,
'client_secret' => $this->client->secret,
'scope' => $scope
];
if($grantType !== 'social'){
$params['username'] = $request->username ?: $request->email;
}
$request->request->add($params);
$proxy = Request::create('oauth/token', 'POST');
return Route::dispatch($proxy);
}
When I put invalid credentials, it returns:
{
"error": "invalid_credentials",
"error_description": "The user credentials were incorrect.",
"message": "The user credentials were incorrect."
}
I want to change this message because I want the message to depend on the language.
Not sure but i try my best to answer you.
use League\OAuth2\Server\Exception\OAuthServerException;
public function issueToken(Request $request, $grantType, $scope = "",ServerRequestInterface $service_request) {
$params = [
'grant_type' => $grantType,
'client_id' => $this->client->id,
'client_secret' => $this->client->secret,
'scope' => $scope
];
if($grantType !== 'social'){
$params['username'] = $request->username ?: $request->email;
}
$request->request->add($params);
$proxy = Request::create('oauth/token', 'POST');
throw OAuthServerException::invalidRequest('access_token', object_get($error,
'error.message'));
return Route::dispatch($proxy);
}
Change App\Exceptions\Handler.php under:
public function render($request, Exception $exception)
{
...
$class = get_class($exception);
...
if ($class == 'League\OAuth2\Server\Exception\OAuthServerException' ){
return response()->json([
'code'=>$exception->getHttpStatusCode(),
'error'=>$exception->getMessage(),
'error_type'=>$exception->getErrorType()
],
$exception->getHttpStatusCode());
}
...
return parent::render($request, $exception);
}

laravel register user if the call to an api is returns a valid access token

I want to register a new user : the procedure is to call an api with a client id and a client secret and if everything is ok I save the user. If not I redirect with an error message.
But when I try to redirect to the register route inside my validator I got this error Call to a member function validate() on string.
protected function validator(array $data)
{
$messages = [
'client_secret.size' => 'Secret Id must be exactly 36 characters',
];
$client_id = $data['client_id'];
$client_secret = $data['client_secret'];
$access = $this->getAccessToken($client_id, $client_secret);
if($access == false){
return route('register');
}
return Validator::make($data, [
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6|confirmed',
'role' => 'required|string',
'country' => 'required|string',
'client_id' => 'required|string',
'client_secret' => 'required|string|size:36'
], $messages);
}
I did that before seeing your answer. I think it's similar.
protected function validator(array $data)
{
$messages = [
'client_secret.size' => 'Secret Id must be exactly 36 characters',
'access_token.required' => 'We could not get an access token, make sure that the client id and the client secret are correct'
];
$input = [
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6|confirmed',
'role' => 'required|string',
'country' => 'required|string',
'client_id' => 'required|string',
'client_secret' => 'required|string|size:36',
'access_token' => 'required|string|min:10'
];
$client_id = $data['client_id'];
$client_secret = $data['client_secret'];
$access = $this->getAccessToken($client_id, $client_secret);
if($access == false){
$data['access_token'] = 'false';
}else{
$data['access_token'] = $access ;
}
return Validator::make($data, $input, $messages);
}
This is a wrong implementation. The validator function returns route('register') on failing to get access token this a string returned. But at the same time if the access token is fetched, you return a validator instance. The code that calls this will try to run the validate method which would fail in the first scenario. And the way this function is coded, you can't redirect from within it. If you really need to then you could do something like this
Validator method
if($access == false) {
throw new \Exception('Failed to get access token');
}
Calling logic
try {
$validator = $this->validator($data);
} catch (\Exception $e) {
return redirect()->route('register');
}
if ($validator->fails()) {
// handle
}
OR
Validator method
if($access == false) {
return null;
}
Calling logic
$validator = $this->validator($data);
if ($validator === null) {
return redirect()->route('register');
}
if ($validator->fails()) {
// handle
}

Laravel Passport password grant returns Invalid Credentials Exception

I am trying to setup a SPA that consumes a Laravel API protected with Passport.
I started by creating a new Laravel app specifically for this and I then followed the instructions for setting up passport and set up a password grant client.
I can successfully create a new user, save the user to the database, and log the user in. After that, I try to use the newly created user's information along with the password grant clients id and secret to create an access token. At this point I receive the exception.
I read through the log and I saw where the exception was being thrown. Inside League\OAuth2\Server\Grant\PasswordGrant the validateUser method has the following:
if ($user instanceof UserEntityInterface === false) {
$this->getEmitter()->emit(new RequestEvent(RequestEvent::USER_AUTHENTICATION_FAILED, $request));
throw OAuthServerException::invalidCredentials();
}
Seeing this I implemented the UserEntityInterface on my user model and implemented the getIdentifier method but I still receive the Exception. I'm really not too sure where to go from here, any help would be greatly appreciated. Below is some of my code.
Here is my Registration controller:
class RegisterController extends Controller
{
private $tokenService;
public function __construct(AccessTokenService $tokenService)
{
//$this->middleware('guest');
$this->tokenService = $tokenService;
}
public function register(Request $request)
{
$this->validateWith($this->validator($request->all()));
Log::debug('Validated');
$user = $this->create($request->all());
$this->guard()->login($user);
$this->tokenService->boot(Auth::user());
return response()->json($this->tokenService->getNewAccessToken(), 200);
}
protected function guard()
{
return Auth::guard();
}
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|min:6|confirmed',
'password_confirmation' => 'required'
]);
}
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
}
}
And these are the relevant portions of AccessTokenService:
public function getNewAccessToken() {
$http = new Client();
$client = \Laravel\Passport\Client::where('id', 6)->first();
Log::debug($client->getAttribute('secret'));
Log::debug($this->user->getAttribute('email'));
Log::debug($this->user->getAuthPassword());
$response = $http->post('homestead.app/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => 6,
'client_secret' => $client->getAttribute('secret'),
'username' => $this->user->getAttribute('email'),
'password' => $this->user->getAuthPassword(),
'scope' => '*'
]]);
unset($client);
$status = $response->getStatusCode();
$body = $response->getBody();
Log::debug($body->getContents());
Log::debug($status);
switch($status)
{
case 200:case 201:
case 202:
$tokens = array(
"user_id" => $this->user->getAttribute('id'),
"access_token" => $body['access_token'],
"refresh_token" => $body['refresh_token']
);
$output = ["access_token" => $this->storeTokens($tokens), 'status_code' => $status];
break;
default:
$output = ["access_token" => '', 'status_code' => $status];
break;
}
return $output;
}
private function storeTokens(array $tokens) {
UserToken::create([
"user_id" => $tokens['user_id'],
"access_token" => bcrypt($tokens['access_token']),
"refresh_token" => bcrypt($tokens['refresh_token'])
]);
return $tokens['access_token'];
}
So I figured out the issue. When I was requesting the access token I was passing in the user's email and password but I was passing the hashed password when I needed to pass in the unhashed password.
My request for an access token looked like this:
$response = $http->post('homestead.app/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => 6,
'client_secret' => $client->getAttribute('secret'),
'username' => $this->user->getAttribute('email'),
'password' => $this->user->getAuthPassword(), //Here is the problem
'scope' => '*'
]]);
By passing the Request to the function using the unhashed password like this solved the problem:
$response = $http->post('homestead.app/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => 6,
'client_secret' => $client->getAttribute('secret'),
'username' => $request['email'],
'password' => $request['password'],
'scope' => '*'
]]);
In my case it was magic
when i changed username from email format to simple (alphanumeric only) format it works.
please tell the reason if anyone have for my case.
Thanks

An active access token must be used to query information about the current user in laravel

I am trying to login with facebook using angularjs with laravel. But I am stuck with this error:
{"error":{"message":"An active access token must be used to query
information about the current user.","type":"OAuthExce (truncated...)
Here is my Controller:
public function facebookLogin(Request $request){
$client = new GuzzleHttp\Client();
$params = [
'code' => $request->input('code'),
'client_id' => $request->input('clientId'),
'redirect_uri' => $request->input('redirectUri'),
'client_secret' => Config::get('app.facebook_secret'),
'grant_type'=>'client_credentials'
];
// Step 1. Exchange authorization code for access token.
$accessTokenResponse = $client->request('GET', 'https://graph.facebook.com/v2.5/oauth/access_token', [
'query' => $params
]);
$accessToken = json_decode($accessTokenResponse->getBody(), true);
// Step 2. Retrieve profile information about the current user.
$fields = 'id,email,first_name,last_name,link,name,picture';
/**** problem counted with this request ************/
$profileResponse = $client->request('GET', 'https://graph.facebook.com/v2.5/me', [
'query' => [
'access_token' => $accessToken['access_token'],
'fields' => $fields
]
]);
$profile = json_decode($profileResponse->getBody(), true);
$user = User::where('email', '=', $profile['email'])->first();
if($user) {
Auth::loginUsingId($user->id);
$user_info = Auth::user();
$profile_seen = $user_info->profile_seen;
User::where('id', '=', $user_info->id)->update(array('profile_seen' => 1));
return Response::json(['login' => Auth::check(),'profile_seen' => $profile_seen ]);
}else{
$user = User::create(array(
'username' => $profile['name'],
'email' => $profile['email'],
'first_name' => $profile['first_name'],
'last_name' => $profile['last_name'],
'facebook_id'=> $profile['id']
));
Auth::loginUsingId($user->id,1);
$user_info = Auth::user();
$profile_seen = $user_info->profile_seen;
User::where('id', '=', $user_info->id)->update(array('profile_seen' => 1));
return Response::json(['login' => Auth::check(),'profile_seen' => $profile_seen ]);
}
}
I have encountered this problem. You need to run the composer update. Then run the command composer dump-autoload. This problem has been fixed in version Socialite v2.0.21.

Categories