I'm trying to use Laravel Socialite package over an api. I try to pass the code into my api to fetch the user but it keeps giving me an error:
Fatal error: Call to a member function pull() on null
Since I'm doing the request over an API, I take the following steps.
Send a request to api for the url to fetch the code:
Socialite::with('facebook')->stateless()->redirect()->getTargetUrl()
Then make a request with the above fetched url, which redirects with the code parameter.
Send the code to the api and fetch the user:
$fb_user = Socialite::with('facebook')->user();
This is where it crashes. I'm not sure why.
I've used the package before and it works fine when I just have an app that reloads the page. But when I send it to an api (on a different domain) it crashes. I'm thinking there is some issue with how the code is generated. Is there anyway to fix this?
Just found my answer. Need to use stateless in both calls:
Socialite::with('facebook')->stateless()->redirect()->getTargetUrl()
$fb_user = Socialite::with('facebook')->stateless()->user();
Hope this helps someone.
I made SocialController.php and url (POST request) /api/social-login which accepts provider and access_token.
SocialAccount here is a laravel model where you'll provider and provider_user_id and local database user id. Below is the example of social_accounts table
And in SocialController :
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Hash;
use Illuminate\Http\Request;
use App\User;
use App\SocialAccount;
use Socialite;
class SocialController extends Controller
{
public function social(Request $request) {
$provider = $request->input('provider');
switch($provider){
case SocialAccount::SERVICE_FACEBOOK:
$social_user = Socialite::driver(SocialAccount::SERVICE_FACEBOOK)->fields([
'name',
'first_name',
'last_name',
'email'
]);
break;
case SocialAccount::SERVICE_GOOGLE:
$social_user = Socialite::driver(SocialAccount::SERVICE_GOOGLE)
->scopes(['profile','email']);
break;
default :
$social_user = null;
}
abort_if($social_user == null , 422,'Provider missing');
$social_user_details = $social_user->userFromToken($request->input('access_token'));
abort_if($social_user_details == null , 400,'Invalid credentials'); //|| $fb_user->id != $request->input('userID')
$account = SocialAccount::where("provider_user_id",$social_user_details->id)
->where("provider",$provider)
->with('user')->first();
if($account){
return $this->issueToken($account->user);
}
else {
// create new user and social login if user with social id not found.
$user = User::where("email",$social_user_details->getEmail())->first();
if(!$user){
// create new social login if user already exist.
$user = new User;
switch($provider){
case SocialAccount::SERVICE_FACEBOOK:
$user->first_name = $social_user_details->user['first_name'];
$user->last_name = $social_user_details->user['last_name'];
break;
case SocialAccount::SERVICE_GOOGLE:
$user->first_name = $social_user_details->user['name']['givenName'];
$user->last_name = $social_user_details->user['name']['familyName'];
break;
default :
}
$user->email = $social_user_details->getEmail();
$user->username = $social_user_details->getEmail();
$user->password = Hash::make('social');
$user->save();
}
$social_account = new SocialAccount;
$social_account->provider = $provider;
$social_account->provider_user_id = $social_user_details->id;
$user->social_accounts()->save($social_account);
return $this->issueToken($user);
}
}
private function issueToken(User $user) {
$userToken = $user->token() ?? $user->createToken('socialLogin');
return [
"token_type" => "Bearer",
"access_token" => $userToken->accessToken
];
}
}
EDIT:
I have created package for the same https://packagist.org/packages/pimplesushant/laravelsocialiteapi
Related
I am trying to create a login token for a user after they register on my application and have verified their mobile device using an OTP sent via sms. The problem is that, when a user logs in, the token is created perfectly. However, when I try to create this token on registration, no token is generated. When a user registers, I want to immediately log them into my app.
Note: This is an app using an API. The login logic works perfectly.
Question Is there anywhere I might be missing it. Have been debugging but no success.
<?php
namespace App\Http\Controllers\Admin;
use App\Models\User;
use App\Exceptions\Handler;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Validator;
use App\Http\Resources\LoginResource;
class RegisterController extends Controller
{
public function verifyOTP(Request $request){
$validate = Validator::make($request->all(), [
'otp' =>'required|digits:4',
'cellphone' =>'required|digits:10',
]);
if ($validate->fails()){
return response($validate->errors(), 400);
}
$user = DB::table('users')
->where('cellphone', $request->cellphone)
->where('otp', $request->otp)
->first();
if( !$user ){
return response('Wrong OTP. Try again.', 400);
}else{
$updatedUser = DB::table('users')
->where('cellphone', $request->cellphone)
->update([
'status' => 1,
'otp' => NULL,
'account_verified' => 1,
]);
//allocate the user with an authentication token
$loggedInUser = new LoginResource($user);
/******THE FOLLOWING LINE IS THE ONE WITH THE PROBLEM WHERE THE TOKEN IS NOT BEING CREATED. SAYS UNDEFINED METHOD createToken******/
$token = $user->createToken('registration-login-token');
return response([
'user' => $loggedInUser,
'token' => $token->plainTextToken,
], 200);
}
}
}
The error i get is
Error: Call to undefined method stdClass::createToken() in file .../app/Http/Controllers/Admin/RegisterController.php on line 78
Instead of DB you have to use Eloquent Model so use User model instead of DB in below Query :
$user = DB::table('users')
->where('cellphone', $request->cellphone)
->where('otp', $request->otp)
->first();
Hello i am having xero API
i am trying to integrate it with my laravel project , i am getting above error I am using following laravel package for same.
github package link : https://github.com/webfox/laravel-xero-oauth2/
----------------routes-----------------
Route::get('/manage/xero', [XeroController::class, 'index'])->name('xero.auth.success');
Route::get('xero/auth/callback', [XeroController::class, 'data'])->name('xero.auth.callback');
---controller-----------------
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Webfox\Xero\OauthCredentialManager;
class XeroController extends Controller
{
public function index(Request $request, OauthCredentialManager $xeroCredentials)
{
try {
// Check if we've got any stored credentials
if ($xeroCredentials->exists()) {
/*
* We have stored credentials so we can resolve the AccountingApi,
* If we were sure we already had some stored credentials then we could just resolve this through the controller
* But since we use this route for the initial authentication we cannot be sure!
*/
$xero = resolve(\XeroAPI\XeroPHP\Api\AccountingApi::class);
$organisationName = $xero->getOrganisations($xeroCredentials->getTenantId())->getOrganisations()[0]->getName();
$user = $xeroCredentials->getUser();
$username = "{$user['given_name']} {$user['family_name']} ({$user['username']})";
}
} catch (\throwable $e) {
// This can happen if the credentials have been revoked or there is an error with the organisation (e.g. it's expired)
$error = $e->getMessage();
}
return view('xero', [
'connected' => $xeroCredentials->exists(),
'error' => $error ?? null,
'organisationName' => $organisationName ?? null,
'username' => $username ?? null
]);
}
}
Your xero/auth/callback route is routed to the XeroController::data() function, which does not exist.
Looking at that package, it looks like it already registers a route for xero/auth/callback, pointing to the AuthorizationCallbackController in the package. I'm assuming you just need to remove your manually defined route.
I am working on Laravel Project It require to add Google sheets & after add this it must be shareable at my site
this my Code.
When I open the link
http://localhost:8000/viewsheet/18ioWbPXjd1RM2wqJuJ0eFzkYAfC03OT9_X5tWJEV3uU/sheet/Phrasebook
from another browser, it gives me an error because I am not logged in
how I can make it shareable for all users without others login?
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Sheets;
use Google;
class sheetview extends Controller
{
//
public function __invoke(Request $request, $spreadsheet_id, $sheet_id)
{
//// print_r($request);
// $rows = $request->user()
// ->sheets()
// ->spreadsheet($spreadsheet_id)
// ->sheet($sheet_id)
// ->get();
$user = $request->user();
$token = [
'access_token' => $user->access_token,
'refresh_token' => $user->refresh_token,
'expires_in' => $user->expires_in,
'created' => $user->updated_at->getTimestamp(),
];
// all() returns array
$values = Sheets::setAccessToken($token)- >spreadsheet($spreadsheet_id)->sheet($sheet_id)->all();
print_r($values);
///$headers = $rows->pull(0);
// return view('sheets.viewsheet')->with(compact('headers', 'rows'));
}
}
public function store(Request $request)
{
$booking = ($request->isMethod('put')) ? Booking::findOrFail($request->booking_id) : new Booking;
$booking->checkIn = $request->checkIn;
$booking->checkOut = $request->checkOut;
$booking->room_id = $request->room_id;
$booking->user_id = auth()->user()->id;//not working
if($booking->save()){
return new BookingResource($booking);
}
}
Route::put('/booking','BookingsController#store');//api.php
Here auth()->user()->id is not working but its working find if i use it the same code but route code in routes/web.php
pass guard parameter in auth used like that ..
1. auth('api')->user(); //if u are using api guard ...(web guard)
2. $request->user('api'); //by reqeust class
3. Auth::guard('api')->user() //using Auth facade
use auth:api middleware in your route.
Route::middleware(['auth:api'])->put('/booking','BookingsController#store');
use this way in your controller :
use Illuminate\Support\Facades\Auth
$booking->user_id = Auth::user()->id;
I’m working on a project based on an iOS app (native) who use a webapp (Laravel framework) to communicate.
For exemple, ios user should use Laravel login to use the application.
The laravel part of the project is done and work good on a computer (login,register etc…)
But now i’m thinking how will i communicate with my futur ios App and my webapp using laravel framework. I dont know any ways to do that, maybe i need a special framwork on my ios app ?
I have no idea, can you help me ?
Thanks in advance
This is a loaded question.... My personal preference is to set up a set of API controllers so you can control them independently and version them.
1) Create a sub-set of controllers # /app/controllers/api/v1
2) Give them all a namespace of api/v1
<?php namespace api\v1;
3) Import whatever classes you need into the new namespace
<?php namespace api\v1;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Response;
use Usage;
use Auth;
4) Install an oAuth2 package
5) Set up routes that generate and validate tokens and place your protected routes in a route group. (my example below.)
Route::group(['prefix' => 'api/v1', 'before' => 'apiErrors'], function()
{
Route::post('accessToken', function()
{
return AuthorizationServer::performAccessTokenFlow();
});
Route::group(['before' => 'oauth|setUser'], function()
{
Route::resource('usages', 'api\v1\UsagesController');
Route::resource('connections', 'api\v1\ConnectionsController');
Route::resource('users', 'api\v1\UsersController');
});
});
6) Set up your new api controllers to return data in a manner that a mobile app can use (JSON)
public function index()
{
$usages = Usage::with('device.model.manufacturer')
->where('user_id', Auth::user()->id)
->get();
return Response::json($usages, $this->responseCode, $this->accessControl);
}
thanks for your complete answer ! but i have done an simple API controller without oAuth2 package. My controller for the moment just return true or false if login is okay and it works good. here my code for other people...
public function trylogin() {
if (Auth::attempt(array('email'=>Input::get('email'), 'password'=>Input::get('password'))) || Auth::attempt(array('username'=>Input::get('username'), 'password'=>Input::get('password')))) {
return Response::json(array('status' => 'OK'));
} else {
return Response::json(array('status' => 'FAIL'));
}
}
here my api routes
Route::resource('api/v1', 'ApiController');
Route::get('api/v1_hello', 'ApiController#sayhello');
Route::get('api/v1_login', 'ApiController#trylogin')
what do you think about security managment ? i can make my own token system validation on ios ?
EDIT
i finally found a solution, here the function in my ApiController :
you just need to send to your api from iOS the token generate by Facebook or Google connexion. and in my case add a network parameter.
public function registerOrLoginFromSocialNetWorkV1(){
if (Input::get('email') && Input::get('sn_id')) {
//sn = social network
if (User::where('email','=', Input::get('email'))->count() != 0) {
$user = User::where('email','=', Input::get('email'))->first();
$user->fb_id = Input::get('sn_id');
$user->save();
//return 'email already used';
}
else{
if (User::where('fb_id','=', Input::get('sn_id'))->count() == 0) {
$user = new User;
$user->firstname = Input::get('firstname');
$user->lastname = Input::get('lastname');
$user->username = Input::get('username');
$user->email = Input::get('email');
$user->fb_id = Input::get('sn_id');
$user->fk_role = 3;
$user->yearofbirth = Input::get('birthday');
//$user->yearofbirth = substr($me['birthday'],6,9);
if (Input::get('sex') == 'male') {
$user->sex = 1;
}
else{
$user->sex = 0;
}
$user->save();
Userslog::log('api_register_social_network');
}
else{
$user = User::where('fb_id','=', Input::get('sn_id'))->first();
if (!$user->yearofbirth){
$user->yearofbirth = Input::get('birthday');
$user->save();
}
}
}
//dd($user);
Auth::login($user);
$follows = Follow::where('user_id','=',$user->id)->get();
return Response::json(array('user' => $user,'follows' => $follows));
}
else{
return 'error';
}
}