"Attempt to read property \"id\" on null", Create access token error with laravel passport, laravel 9, php 8.2.2 - laravel-9

devs,
so I have been struggling with this problem for about 10 hours now, and I can't seem to find a solution online, worst is that I don't even know why it happens.
I am working on a project which uses PHP LARAVEL as the backend and I started writing the API for the flutter frontend to consume then I ran into this error while trying to test the API endpoint for registering and logging in.
The problem is the process fails with this error when I try to generate or create a token for the registered user or logged-in user.
Here a snapshot of my register function
public function store(Request $request)
{
$validated = Validator::make($request->all(),[
"email" => "required|email",
"password" => 'required',
"first_name"=> "required",
"last_name" => "required",
"phone_number" => 'required',
]);
if ($validated->fails()) {
return response()->json(['errors' => "Invalide credentials"], 403);
}
$user = User::create(
// [
// 'first_name' => $request->first_name,
// 'last_name'=> $request->last_name,
// 'email' => $request->email,
// 'password' => bcrypt($request->password),
// 'phone_number' => $request->phone_number,
// ]
$request->toArray()
);
Auth::guard('api')->check($user);
// $newUser = User::find($user->id);
$token = $user->createToken('authToken')->accessToken;
// return $token;
return response(['token' => $token, 'first_name'=>$user->first_name, 'email'=>$user->email ], 200);
}
The login and register functions all look the same at this point.
Error-causing code is :
$token = $user->createToken('authToken')->accessToken;
Please I am open to your suggestions, thanks.

I finally found a solution for this error and I believe it will help anyone out there with a similar problem.
The problem originates from the fact that your application is unable to asign a unique id to your client, remember your website or mobile app is a client to the backend with also(your mobile app or website) might have other users, so laravel passport will need to identify it with a unique id, below are some of the steps i used to fix this error.
First it originates because during the passport installation, i forgot to install
Blockquote
--uuids
If you have a similar error, follow the steps below to fix:
NOTE: You must have laravel passport installed already, if not, them follow the complete installtion guide Here
Step 1:
Install passport uuids
php artisan passport:install --uuids
Your result will look something like
After creating, the uuid for your application, you will have to include it in your .env file as such:
PASSPORT_PERSONAL_ACCESS_CLIENT_ID=986eb40c-0458-4b6e-bead-ea2fc4987033
PASSPORT_PERSONAL_ACCESS_CLIENT_SECRET=VXLdTpqWK9i3CBqFwZgje5fuerQ5Uf2lvwXJqBoP
And there you go, you can now try to do what you couldn't do before.

Related

Migrate SSL Config to Elytron

I am trying to migrate a project from using the Legacy Security to using Elytron. I followed the steps in the documentation: https://access.redhat.com/documentation/en-us/red_hat_jboss_enterprise_application_platform/7.1/html/migration_guide/migrating_to_elytron#migrate_ssl_configurations
I verified it first by running:
/subsystem=undertow/server=default-server/https-listener=https:read-attribute(name=security-realm)
Result:
{
"outcome" => "success",
"result" => "ApplicationRealm"
}
Then I followed the steps in the documentation to create a key-store, key-manager, server-ssl-context, and switched the https-listener. And reloaded the server.
/subsystem=elytron/key-store=KeyStore:add(path=$keystore_file,type=JKS,credential-reference={clear-text=$keystore_password})
/subsystem=elytron/key-manager=KeyManager:add(key-store=KeyStore,credential-reference={clear-text=$keystore_password})
/subsystem=elytron/server-ssl-context=SSLContext:add(key-manager=KeyManager)
batch
/subsystem=undertow/server=default-server/https-listener=https:undefine-attribute(name=security-realm)
/subsystem=undertow/server=default-server/https-listener=https:write-attribute(name=ssl-context,value=SSLContext)
run-batch
Then I checked the https-listener again:
/subsystem=undertow/server=default-server/https-listener=https:read-attribute(name=security-realm)
But the result was undefined.
{
"outcome" => "success",
"result" => "Undefined"
}
When I check the standalone-full-ha.xml the SSLContext is there. Is there any other ways to check if the migration is ok?
It's doing exactly what you have told it to do, you are calling undefine, then reading back what you undefined

Laravel passport ( can`t understand)

I read a lot of articles and watched a lot of videos about Laravel passport but still can not understand some things.
I have an application which works with Laravel 5.5 + vueJs. All requests to the back-end are sent via axios. All my routes are located in api.php
Route::middleware('api')->group(function(){
Route::get('/prepare/', 'CompgenApiController#prepareDefault');
Route::post('/replace/', 'CompgenApiController#replaceImage');
Route::get('/replaceall/', 'CompgenApiController#replaceAllImages');
Route::get('/collage/', 'CompgenApiController#collage'); //#todo переделать на POST
Route::get('/generate/', 'CompgenApiController#generate');
Route::post('/upload/', 'CompgenApiController#userUpload');
Route::post('/reupload/', 'CompgenApiController#moderationReupload');
});
Also I have a VK bot that sends requests to the same routes.
At the moment I have some difficulties. For some routes, I need to check that the user is authorized (but this is an optional condition) and if it is true I need to write user id to the database. For me it was a surprise that
Auth :: check
returned false though I was authorized. After some searches I learned that the session that starts after authorization is not connected with the API and I was recommended to use Passport. I can not understand the following things
Do I need to use a passport if requests are sent from my application from vueJs?
How to register users? Do I have to issue my token for each new user?
How can I verify that the user is authorized?
In some cases I need to check that the user is authorized but if it is not so then do not interfere with the request. How can I do that?
Maybe in my case I do not need a passport at all?
Passport is an oAuth2 server implementation, essentially, it allows you to authenticate users by passing a token with each request. If you do not want to authenticate a user, then you do not need to pass the token and passport doesn't get involved.
In terms of a Laravel app, if you are consuming your API from your own frontend, you probably just want to use the implicit grant. Here's how you set that up:
1) Install passport and add it the PassportServiceProvider to config/app.php
2) php artisan migrate to setup the passport migrations
3) php artisan passport:install - to set up your oAuth server
4) In the User model add the Laravel\Passport\HasApiTokens trait, like so:
namespace App;
use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
// Other model methods
}
5) Setup the passport routes by adding the following to the boot method of your app\Providers\AuthServiceProviders.php:
\Laravel\Passport\Passport::routes();
6) Change your api driver in config/auth.php to token:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],
That sets up passport, now all you need to do to allow your app to consume your api is to add the CreateFreshApiToken Middleware to web in app/Http/Kernel.php, which handles all the token logic:
'web' => [
// ..Other middleware...
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
],
Now all you need to do to protect a route is to use the auth:api middleware on that route:
Route::middleware('auth:api')->get('/profile','Api\UsersController#edit');
That should all work fine, but you'll also want to register a new user. All you do is add the auth routes as normal to web.php:
Route::post('/login', 'Auth\LoginController#login');
Route::post('/logout', 'Auth\LoginController#logout');
Route::post('/register', 'Auth\RegisterController#register');
You can then simply maks a post request to those routes and Laravel will handle all the token stuff for you.
That handles api routes that require authentication, however, you also mentioned that you want to check if a user is authenticated, but not necessarily lock the route, to do that you can simply use:
Auth::guard('api')->user();
Which will get the authenticated user, so you could do something like:
public function getGreeting(){
$user = Auth::guard('api')->user();
if($user !== null) {
return response()->json(["message" => "Hello {$user->name}"], 200);
}
return response()->json(["message" => "Hello Guest"], 200);
}
That's it. Hopefully, I've covered everything there.

Passport - "Unauthenticated." - Laravel 5.3

I hope someone could explain why I'm unauthenticated when already has performed a successfull Oauth 2 authentication process.
I've set up the Passport package like in Laravel's documentation and I successfully get authenticated, receives a token value and so on. But, when I try to do a get request on, let say, /api/user, I get a Unauthenticated error as a response. I use the token value as a header with key name Authorization, just as described in the docs.
Route::get('/user', function (Request $request) {
return $request->user();
})->middleware("auth:api");
This function is suppose to give back my self as the authenticated user, but I'm only getting Unauthenticated. Likewise, if I just return the first user, I'm again getting Unauthenticated.
Route::get('/test', function(Request $request) {
return App\User::whereId(1)->first();
})->middleware("auth:api");
In a tutorial from Laracast, guiding through the setup of Passport, the guider doesn't have the ->middleware("auth:api") in his routes. But if its not there, well then there's no need for authentication at all!
Please, any suggestions or answers are more then welcome!
You have to set an expiration date for the tokens you are generating,
set the boot method in your AuthServiceProvider to something like the code below and try generating a new token. Passports default expiration returns a negative number
public function boot()
{
$this->registerPolicies();
Passport::routes();
Passport::tokensExpireIn(Carbon::now()->addDays(15));
Passport::refreshTokensExpireIn(Carbon::now()->addDays(30));
}
Check your user model and the database table, if you have modified the primary id field name to say something other than "id" or even "user_id" you MIGHT run into issues. I debugged an issue regarding modifying the primary id field in my user model and database table to say "acct_id" instead of keeping it as just "id" and the result was "Unauthenticated" When I tried to get the user object via GET /user through the auth:api middleware. Keep in mind I had tried every other fix under the sun until I decided to debug it myself.
ALSO Be sure to UPDATE your passport. As it has had some changes made to it in recent weeks.
I'll link my reference below, it's VERY detailed and well defined as to what I did and how I got to the solution.
Enjoy!
https://github.com/laravel/passport/issues/151
I had this error because of that I deleted passport mysql tables(php artisan migrate:fresh), php artisan passport:install helps me. Remember that after removing tables, you need to re-install passport!
I had exactly the same error because I forgot to put http before the project name.
use Illuminate\Http\Request;
Route::get('/', function () {
$query = http_build_query([
'client_id' => 3,
'redirect_uri' => 'http://consumer.dev/callback',
'response_type' => 'code',
'scope' => '',
]);
// The redirect URL should start with http://
return redirect('passport.dev/oauth/authorize?'.$query);
});
Route::get('/callback', function (Request $request) {
$http = new GuzzleHttp\Client;
$response = $http->post('http://passport.dev/oauth/token', [
'form_params' => [
'grant_type' => 'authorization_code',
'client_id' => 3,
'client_secret' => 'M8y4u77AFmHyYp4clJrYTWdkbua1ftPEUbciW8aq',
'redirect_uri' => 'http://consumer.dev/callback',
'code' => $request->code,
],
]);
return json_decode((string) $response->getBody(), true);
});

How to do a Sign Up with OAuth (facebook, twitter, google)?

I use Laravel (5) as my php framework, it recently added a library for social authentication (facebook, google, twitter and github).
I've been wondering how would you do a Sign Up with OAuth, a login can easily be done by getting the user's email via OAuth, checking if it exists in your DB, and if it does, then log in that user. But how would you do the Sign Up?
Mathius - I've recently been working on a site doing something similar to what you've described and this is what has worked for me:
public function syncUserDetails($userData)
{
// First I check to see if there is a user in the DB
// with the oAuth email address
if ( $user = $this->user->where('email', $userData->email)->first() )
{
// If there is a user, I simply update their local info
// with what is on their oAuth account
$user->token = $userData->token;
$user->google_id = $userData->id;
$user->name = $userData->name;
$user->avatar = $userData->avatar;
$user->first_name = $userData->user['given_name'];
$user->last_name = $userData->user['family_name'];
$user->save();
return $user;
}
// Otherwise, if the user doesn't already exist,
// I create them in my local user's DB
return $this->user->firstOrCreate([
'email' => $userData->email,
'token' => $userData->token,
'google_id' => $userData->id,
'name' => $userData->name,
'avatar' => $userData->avatar,
'first_name' => $userData->user['given_name'],
'last_name' => $userData->user['family_name']
]);
}
This is what I'm using to log in a user. However, you could just as easily run this alongside your regular Laravel login method.

Paypal REST API invalid credentials

I use the REST api in my nodejs application.
All is working good with sandbox but when i update with live credentials i get:
{ [Error: Response Status : 401]
response:
{ error: 'invalid_client',
error_description: 'The client credentials are invalid',
httpStatusCode: 401 },
httpStatusCode: 401 }
I updated my account to buisness but still not working, i use the live endpoint and Live credentials.
What should i do in order to make this work?
I had the same issue using PayPalSDK/rest-sdk-nodejs and solved passing with the configuration parameters (host, client_id, client_secret, ...) also the parameter 'mode' set to 'live'. Otherwise the default mode used by the library is 'sandbox' and hence the impossibility to use the live credentials.
As matteo said, if you switch from dev to live environment, only updateing the client id and secret isn't enough. You need to set the ApiContext-Mode to "live".
PayPals PHP REST-API-SDK comes with some great samples. Take a look at the bootstrap.php in /vendor/paypal/rest-api-sdk-php/sample/ in line 84. There are some configurations happening, after getting the api context.
<?php
$apiContext = new ApiContext(
new OAuthTokenCredential(
$clientId,
$clientSecret
)
);
// Comment this line out and uncomment the PP_CONFIG_PATH
// 'define' block if you want to use static file
// based configuration
$apiContext->setConfig(
array(
'mode' => 'sandbox',
'log.LogEnabled' => true,
'log.FileName' => '../PayPal.log',
'log.LogLevel' => 'DEBUG', // PLEASE USE `INFO` LEVEL FOR LOGGING IN LIVE ENVIRONMENTS
'cache.enabled' => true,
// 'http.CURLOPT_CONNECTTIMEOUT' => 30
// 'http.headers.PayPal-Partner-Attribution-Id' => '123123123'
//'log.AdapterFactory' => '\PayPal\Log\DefaultLogFactory' // Factory class implementing \PayPal\Log\PayPalLogFactory
)
);