I am trying to find the logged in user in my application using Auth but i get trying to get property of non-object which i understand clearly that it is returning null.
In my code below, an event triggers my webhook and post is sent to the address below. The function orderCreateWebhook triggers but that is where the error comes from..
The line $get_template = Order::where('id', Auth::user()->id);. Why is Auth returning null please? I am logged as well because i use auth in this same controller for another function which works fine.
Is it because it a webhook ?
Controller
public function registerOrderCreateWebhook(Request $request)
{
$shop = "feas.myshopify.com";
$token = "8f43d89a64e922d7d343c1173f6d";
$shopify = Shopify::setShopUrl($shop)->setAccessToken($token);
Shopify::setShopUrl($shop)->setAccessToken($token)->post("admin/webhooks.json", ['webhook' =>
['topic' => 'orders/create',
'address' => 'https://larashop.domain.com/order-create-webhook',
'format' => 'json'
]
]);
}
public function orderCreateWebhook(Request $request)
{
$get_template = Order::where('id', Auth::user()->id);
$baseurl = "https://apps.domain.net/smsapi";
$query = "?key=7e3e4d4a6cfebc08eadc&to=number&msg=message&sender_id=Shopify";
$final_uri = $baseurl.$query;
$response = file_get_contents($final_uri);
header ("Content-Type:text/xml");
}
In your function registerOrderCreateWebhook you appear to be making a request to shopify api and providing your webhook as the address which shopify will redirect the user to upon success. If this is correct, that request does not know about the user who generated the original request that made the api request since the request is coming from a completely different origin.
You would need to pass some key along with the url and then obtain the user within orderCreateWebhook. Something like:
Shopify::setShopUrl($shop)->setAccessToken($token)->post("admin/webhooks.json",
['webhook' =>
['topic' => 'orders/create',
'address' => 'https://larashop.domain.com/order-create-webhook/some-unique-key',
'format' => 'json'
]
]);
My suggestion would be to have a unique hash stored somewhere that relates back to the user in your system, perhaps a column in your users table. I wouldn't use the user_id for security reasons. So you would end up with something like:
//route
Route::get('/order-create-webhook/{uniqueKey}', 'YourController#orderCreateWebhook');
//or
Route::post('/order-create-webhook/{uniqueKey}', 'YourController#orderCreateWebhook');
// depending on the request type used by api which calls this endpoint
// controller function
public function orderCreateWebhook($uniqueKey, Request $request)
{
$user = User::where('unique_key', $uniqueKey)->first();
$get_template = Order::where('id', Auth::user()->id);
$baseurl = "https://apps.domain.net/smsapi";
$query = "?key=7e3e4d4a6cfebc08eadc&to=number&msg=message&sender_id=Shopify";
$final_uri = $baseurl.$query;
$response = file_get_contents($final_uri);
header ("Content-Type:text/xml");
}
Is it because it a webhook ?
Yes, you can't use sessions in a webhook. It's the shopify server which is making the call. You should read the doc, it may exist a way to give an unique identifier in your call to shopify api and get it back in the webhook to find your user associated.
just use this to get authenticated user
use the facade in your class/Controller
use Illuminate\Support\Facades\Auth
public function getAuthUser(){
$user = Auth::user()
if(!is_null($user)
{
//user is authenticated
}
else
{
// no user
}
}
Related
in one of my projects i want to add a google one tap login for that i followed instructions as mentioned.
The front end is working fine but there is issue with the backend.
Here is my code.
I have added this script to the header.
and this code after body open
<div id="g_id_onload"
data-client_id="#####################.googleusercontent.com"
data-login_uri="/login/google/oneTap"
data-_token="{{csrf_token()}}"
data-method="post"
data-ux_mode="redirect"
data-auto_prompt="true">
</div>
This is the route
Route::get('/login/google/oneTap', [App\Http\Controllers\SocialLoginController::class, 'oneTap']);
In an article regarding one, tap login author told that it requires a post method but there is clarification on how to add a post method.
This is the article.
https://www.teachnep.com/blog/how-to-add-one-tap-login-to-laravel-project#
My backend code.
public function oneTap(REQUEST $request)
{
$token = $request->credential;
$tokenParts = explode('.', $token);
$tokenHeader = base64_decode($tokenParts[0]);
$tokenPayload = base64_decode($tokenParts[1]);
$jwtHeader = json_decode($tokenHeader);
$jwtPayload = json_decode($tokenPayload);
$user = $jwtPayload;
return $user;
}
It returns null;
Any help would be appreciated.
You must define your route using the POST verb instead of GET.
For example:
Route::post('/login/google', [GoogleSignInController::class, 'login'])
->name('login.google');
Even though you can verify the "ID Token" (this is how Google refers to the credential param) by yourself, it is recommended to use the official Google API Client Library.
You can add it to your project using Composer:
composer require google/apiclient
In addition to validate the credential field, you should validate the CSRF token provided in the g_csrf_token field.
To summarize:
/**
* Validate the "ID Token" using the Google API Client Library.
* https://developers.google.com/identity/gsi/web/guides/verify-google-id-token
*/
public function login(Request $request)
{
if ($_COOKIE['g_csrf_token'] !== $request->input('g_csrf_token')) {
// Invalid CSRF token
return back();
}
$idToken = $request->input('credential');
$client = new Google_Client([
'client_id' => env('GOOGLE_CLIENT_ID')
]);
$payload = $client->verifyIdToken($idToken);
if (!$payload) {
// Invalid ID token
return back();
}
dd($payload);
}
Note that I printed the $payload at the end:
You may want to use the $payload['sub'] that represents the user id to register / authenticate this user in your application, as well as its name and picture.
I am implementing facebook data deletion callback but I got really lost and i can't continue on the JSON response that facebook is expecting.
Return a JSON response that contains a URL where the user can check the status of their deletion request and an alphanumeric confirmation code. The JSON response has the following form:
{ url: '<url>', confirmation_code: '<code>' }
that is the part that I got lost and stuck. My question is
what is the URL should do or show.
what is the logic between the confirmation code
so far here is what I did on my controller.
<?php
namespace App\Http\Controllers\User\Auth\Socialite;
use App\Models\User;
use Illuminate\Http\Request;
class FacebookSocialLoginController extends SocialLoginFactory
{
public function provider(): string
{
return 'facebook';
}
public function dataDeletionCallback(Request $request)
{
$signed_request = $request->get('signed_request');
$data = $this->parse_signed_request($signed_request);
$user_id = $data['user_id'];
// here will delete the user base on the user_id from facebook
User::where([
['provider' => 'facebook'],
['provider_id' => $user_id]
])->forceDelete();
// here will check if the user is deleted
$isDeleted = User::withTrashed()->where([
['provider' => 'facebook'],
['provider_id' => $user_id]
])->find();
if ($isDeleted ===null) {
return response()->json([
'url' => '', // <------ i dont know what to put on this or what should it do
'code' => '', // <------ i dont know what is the logic of this code
]);
}
return response()->json([
'message' => 'operation not successful'
], 500);
}
private function parse_signed_request($signed_request) {
list($encoded_sig, $payload) = explode('.', $signed_request, 2);
$secret = config('service.facebook.client_secret'); // Use your app secret here
// decode the data
$sig = $this->base64_url_decode($encoded_sig);
$data = json_decode($this->base64_url_decode($payload), true);
// confirm the signature
$expected_sig = hash_hmac('sha256', $payload, $secret, $raw = true);
if ($sig !== $expected_sig) {
error_log('Bad Signed JSON signature!');
return null;
}
return $data;
}
private function base64_url_decode($input) {
return base64_decode(strtr($input, '-_', '+/'));
}
}
what is the URL should do or show.
The purpose of this URL, is what the documentation said - to provide a way for the user, to check on the status of their deletion request.
Not all apps will be able to delete all personal user data immediately, the moment the user requests it.
Some might need to keep a subset of the data for legal reasons; others might simply need some extra processing time, because the process can not be handled in a totally automated matter, and a human needs to get involved.
So the user is given this status check URL in response to their request – so that they can go visit that URL tomorrow, or two weeks or six months from now, and check on the status of their deletion request - were you able to delete all data by now, will it still take some time, is there some data that won’t be deleted for legal reasons, etc.
what is the logic between the confirmation code
Just a different way to access the same information. Maybe checking the status via the URL you provided is not enough for the user, so they might want to call or send an email to your support staff, to inquire about the status of their deletion request. Then they can give your support people that code, and they can go look up the necessary information via that.
If you check the code examples in the documentation, they are using the same code value in the status check URL, and as the confirmation code. So you can use the same code for both.
Create it, store it in your database, and associate the status of a particular user’s deletion request with that code.
I'm developing a webpage with Laravel 8 and I have issues with fetching a patron details by id from Patreon API. Here is my use case.
I’ve added "Login with Patreon" option to my webpage, and it works well. When someone login with Patreon successfully, I store her/his Patreon id and set remember token to login the member automatically when she/he visits my page next time.
The first login process is fine. The problem occurs when my Patron visits my page next time. Because I want to check whether I received any payment before I let she/he see all content. That’s why I need to get my patron details from a middleware. To do that I tried:
fetch_user() returns my account details instead of logged-in user.
fetch_user() with the access token that returns from Patreon when
someone login, returns unauthorized.
fetch_member_details() doesn’t work with the id I passed, which is an
integer like 5484646 because it requires a very long string like
55153fds-f45fd5sfs-fds42ds, I don't know what it's.
fetch_page_of_members_from_campaign() and fetch_member_details()
together to get the proper ID, but it takes ages to get data, which
is unacceptable.
So, how can it be done?
https://further-reading.net/2020/06/getting-names-of-your-patreon-patrons-by-tier/
This might be useful. I believe, there is not a direct single API for this, but you can -
First fetch all campaigns/tiers data
And then fetch patrons for each campaign/tier
I like to answer my question for those who need some help.
First of all, I use the official PHP package by Patreon
I've created a middleware to check if the user should be authorized again. In order to prevent the same process every single time, I set timeout to users table and check if it still has time to expire. If it does, no need to do anything. Of course, this is my use case, but without that explanation, some parts of the code can be nonsense to you.
// App\Http\Middleware\AuthenticateMember.php
public function handle(Request $request, Closure $next)
{
if (!Auth::check()) {
return $next($request);
}
if (Carbon::parse(Auth::user()->timeout)->isFuture()) {
return $next($request);
}
$this->refreshCredentials();
return $next($request);
}
If "timeout" isn't in the future, refreshCredentials method will be called. This is a method, which will trigger binding AuthGatewayContract to the service container.
// App\Trait\Users.php
public function refreshCredentials()
{
$gateway = App::make('App\Services\AuthGatewaysContract');
$gateway->ensureUserStillAuthenticated();
}
public function handleUserRecord($user)
{
return User::updateOrCreate([
'email' => $user['email']
], $user);
}
public function attemptToLogin($user, $remember = true)
{
Auth::login($user, $remember);
event(new Registered($user));
}
This is how the binding works:
// App\Providers\AppServiceProvider.php
public function register()
{
$this->app->singleton(AuthGatewaysContract::class, function () {
$routeParts = explode('/', url()->current());
$gateway = array_pop($routeParts); // this is how I know which "Login with ..." button is clicked.
$isGateway = Gateway::where('name', $gateway)->first();
$gateway = $isGateway ? ucfirst($gateway) : ucfirst(Auth::user()->gateway->name);
$class = "\App\Services\AuthGateways\\$gateway";
return new $class();
});
}
So Patreon.php is active gateway now, and ensureUserStillAuthenticated can be called:
// App\Services\AuthGateways\Patreon.php
public function ensureUserStillAuthenticated()
{
$this->authenticate([
'access_token' => Auth::user()->access_token,
'refresh_token' => Auth::user()->refresh_token,
]);
}
private function authenticate($tokens)
{
$patron = $this->fetchUserFromGateway($tokens);
$user = $this->handleResponseData($patron, $tokens);
$user = $this->handleUserRecord($user);
return $this->attemptToLogin($user);
}
private function fetchUserFromGateway($tokens)
{
// This is the only function that communicate with Patreon-php package.
$api_client = new API($tokens['access_token']);
return $api_client->fetch_user();
}
private function handleResponseData($data, $tokens)
{
return [
'name' => $data['data']['attributes']['full_name'],
'email' => $data['data']['attributes']['email'],
'password' => Hash::make(Str::random(24)),
'role_id' => $this->assignRoleId($data),
'payment_id' => Payment::where('name', 'patreon')->first()->id,
'gateway_id' => Gateway::where('name', 'patreon')->first()->id,
'access_token' => $tokens['access_token'],
'refresh_token' => $tokens['refresh_token'],
'timeout' => Carbon::today()->addMonth()->toDateString()
];
}
I am a newbie to JWT Token System in laravel 5 and using tymon JWT Auth
I managed to create my custom JWT token and my code as follows
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Tymon\JWTAuth\JWTManager as JWT;
use JWTAuth;
use JWTFactory;
use Tymon\JWTAuth\Exceptions\JWTException;
public function login(Request $request)
{
$customClaims = ['foo' => 'bar', 'baz' => 'bob'];
$payload = JWTFactory::make($customClaims);
$token = JWTAuth::encode($payload);
// return response()->json(compact('token')); // This didnt work?Why?
return response()->json(compact($token))->header('Authorization','Bearer '.$token);
}
public function getUser(){
$token = JWTAuth::parseToken();
echo $token;
}
Here are my following clarifications required
// return response()->json(compact('token'));
Why this gave me an empty json object as {"token":{}}
Is it the right way, i could send my custom data in token and get it back the foo and baz values from the same token?
The output of my code while testing with postman is an empty array. as []. But my headers are added with Authorization →Bearer eyJ0eXAiOiJKV1QiLCJhbG...
Is this correct?
3a. Instead of a simple blank array, i need a success message as 'authorized':true. How can i achieve it?
How should i pass this token back to test. Where should this token be passed using postman. I passed it through Headers as shown in the image
How could i parse this token using laravel and get the custom data i.e foo and baz sent as a token. The method i called is getUser here.
I dont think the token creation is being built properly. Below is working code for login token creation. For this, make sure that the 'user' model under your config/jwt.php is the correct eloquent user model for your application.
$user = array(
'user' => $request->input('email'),
'password' => $request->input('pass')
);
$customClaims= ['usr' => $user['user']];
if(!$token = JWTAuth::attempt($user, $customClaims)){
abort(401);
}
else{
return response()->json(compact('token'));
}
Also included in the above code with the custom claims variable, you were on the right track with that just needs to be passed as a second parameter in the attempt function.
Only the client needs to send the authorization: Bearertoken header to prove that they are who they say they are (I am coming from an android client/server jwt background. So sorry if this doesnt apply to your application).
3a. For any subsequent pages that the user browses to, you simply add an if statement like this
if(!$user = JWTAuth::parseToken()->authenticate()){
abort(401);
}
else{
// Code allowing the user to see protected content
}
See answer to question 3. include an http header with authorization BearerToken
To extract the data from the JWT Payload, you will need to decode the base64 encoded text from the text after the first period in the token and send that to a string. Then run that string through the base64_decode($string) function. That should start to give you some of the payload data.
Hope this helps.
I had the same problem here and i got the following solution:
public function whatEver()
{
$token = JWTAuth::parseToken();
$response = $token->getPayload()->get('foo');
return $response
}
this should return bar.
you can use this method in your user model :
/**
* Return a key value array, containing any custom claims to be added to the JWT.
*
* #return array
*/
public function getJWTCustomClaims()
{
return [
'perms' => '
'
];
}
I'm not able to redirect in my application using:
return redirect('/);
The problem comes from when the user do a login using facebook.
Facebook returns a url that contains #= and seems to block my site execution:
public function createUserFromFacebookInfos( $info )
{
$user = User::firstOrCreate([
'email' => $info->email
]);
$user->name = $info->name;
$user->provider_token = $info->token;
$user->provider_id = 1;
$user->save();
$this->auth->login( $user );
return redirect('/');
}
How can I remove that piece of url?
I have read that that code is added when redirect_uri is missing, but where should I set this redirect_uri?
Make sure that you are propagating the redirect object returned from sub-function out from your main controller function.