Hybridigniter Auth library and social plugin - codeigniter

I have integrated the codeigniter hybrid auth library for social login. I have created the developer key for facebook , google and twitter. When i am trying to login with these api's, i got an error.I am running my application in localhost. Is it a problem while redirecting the url to localhost.
Facebook Authentication:
User has cancelled the authentication or the provider refused the connection.
Google Authentication:
Error: redirect_uri_mismatch
Twitter Authentication:
User has cancelled the authentication or the provider refused the connection.
Controller(hauth):
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class HAuth extends CI_Controller {
public function index()
{
$this->load->view('hauth/home');
}
public function login($provider)
{
log_message('debug', "controllers.HAuth.login($provider) called");
try
{
log_message('debug', 'controllers.HAuth.login: loading HybridAuthLib');
$this->load->library('HybridAuthLib');
if ($this->hybridauthlib->providerEnabled($provider))
{
log_message('debug', "controllers.HAuth.login: service $provider enabled, trying to authenticate.");
$service = $this->hybridauthlib->authenticate($provider);
if ($service->isUserConnected())
{
log_message('debug', 'controller.HAuth.login: user authenticated.');
$user_profile = $service->getUserProfile();
log_message('info', 'controllers.HAuth.login: user profile:'.PHP_EOL.print_r($user_profile, TRUE));
$data['user_profile'] = $user_profile;
$this->load->view('hauth/done',$data);
}
else // Cannot authenticate user
{
show_error('Cannot authenticate user');
}
}
else // This service is not enabled.
{
log_message('error', 'controllers.HAuth.login: This provider is not enabled ('.$provider.')');
show_404($_SERVER['REQUEST_URI']);
}
}
catch(Exception $e)
{
$error = 'Unexpected error';
switch($e->getCode())
{
case 0 : $error = 'Unspecified error.'; break;
case 1 : $error = 'Hybriauth configuration error.'; break;
case 2 : $error = 'Provider not properly configured.'; break;
case 3 : $error = 'Unknown or disabled provider.'; break;
case 4 : $error = 'Missing provider application credentials.'; break;
case 5 : log_message('debug', 'controllers.HAuth.login: Authentification failed. The user has canceled the authentication or the provider refused the connection.');
//redirect();
if (isset($service))
{
log_message('debug', 'controllers.HAuth.login: logging out from service.');
$service->logout();
}
show_error('User has cancelled the authentication or the provider refused the connection.');
break;
case 6 : $error = 'User profile request failed. Most likely the user is not connected to the provider and he should to authenticate again.';
break;
case 7 : $error = 'User not connected to the provider.';
break;
}
if (isset($service))
{
$service->logout();
}
log_message('error', 'controllers.HAuth.login: '.$error);
show_error('Error authenticating user.');
}
}
public function endpoint()
{
log_message('debug', 'controllers.HAuth.endpoint called.');
log_message('info', 'controllers.HAuth.endpoint: $_REQUEST: '.print_r($_REQUEST, TRUE));
if ($_SERVER['REQUEST_METHOD'] === 'GET')
{
log_message('debug', 'controllers.HAuth.endpoint: the request method is GET, copying REQUEST array into GET array.');
$_GET = $_REQUEST;
}
log_message('debug', 'controllers.HAuth.endpoint: loading the original HybridAuth endpoint script.');
require_once APPPATH.'/third_party/hybridauth/index.php';
}
}
/* End of file hauth.php */
/* Location: ./application/controllers/hauth.php */

That Facebook error happened to me. My app had already been authorized but Facebook did not redirect properly after authorization. Go to Facebook>settings>apps and check whether your app is among the authorized ones. If so, delete it and try again.

You may face problem running Facebook and other third party authentications on local host, and it may be because of different reasons. One possible solution you can try is set a virtual domain to access your CI website. http://www.kristengrote.com/blog/articles/how-to-set-up-virtual-hosts-using-wamp gives very clear instruction to set up virtual host on WAMP. and then do our Facebook app's settings accordingly.
You may have to check if relevant ports on your localhost are open, otherwise you may face problem in receiving back the authentication.

Related

Laravel 9 HTTP client exception handling

I'm trying to catch errors that occur during HTTP client operations. If debugging is enabled APP_DEBUG=true then I get an error trace, if it is off, then it comes json response "message": "Server Error". But I need to catch exceptions, it doesn't work. Tried catch (\Illuminate\Http\Client\ConnectionException $e), but it didn't work. What am I doing wrong?
public function ExampleMethod()
{
try {
$response =
Http::withBasicAuth(env('REMOTE_LOGIN'), env('REMOTE_PASSWORD'))
->accept('application/json')
->retry(3, 2000)->timeout(12)
->withBody("dummy body content", "application/json")
->post($host . $url);
if ($response->ok()) {
//Do something
}
} catch (Exception $e) {
dd("CATCH IT");
}
}
There is an example from the documentation, the domain does not exist, and an exception handler should work somewhere, but it does not work
public function catchExceptins()
{
try {
$url = "domain-is-not-exist.com";
$response = Http::get($url);
if ($response->ok()) {
dd("200 OK");
}
//
if($response->failed()){
dd("FAILED");
}
//Below are the handlers that should work,
//but they do not respond when there is no domain
//or for example if the server response is 505
if($response->serverError()) {
dd("FAILED");
}
if($response->clientError()) {
dd("FAILED");
}
$response->throw(function($response, $e){
dd("FAILED");
})->json();
} catch (Exception $e) {
dd($e);
}
}
Laravel's HTTP client wrapper offers a mechanism for handling errors with a bunch of useful methods.
public function ExampleMethod()
{
try{
$response = Http::withBasicAuth(env('REMOTE_LOGIN'), env('REMOTE_PASSWORD'))
->accept('application/json')
->retry(3, 2000)->timeout(12)
->withBody("dummy body content", "application/json")
->post($host . $url);
//Check for any error 400 or 500 level status code
if($response->failed()){
// process the failure
}
//Check if response has error with 500 level status code
if($response->serverError()) {
//process on server error
}
//Check if response has error with 400 level status code
if($response->clientError()) {
//process on client error
}
// It also allows to throw exceptions on the $response
//If there's no error then the chain will continue and json() will be invoked
$response->throw(function($response, $e){
//do your thing
})->json();
}
catch(\Exception $e) {
//$e->getMessage() - will output "cURL error 6: Could not resolve host" in case of invalid domain
}
}
Laravel Docs - Http Client - Exception Handling
When you set APP_DEBUG=false, it just shows a generic error to the end user for security, but should give you the detailed error inside of the Laravel logs. 'All' APP_DEBUG=true does, is make the development process easier by displaying the log on the front end.
Your Laravel logs should be inside of "/storage/logs".
https://laravel.com/docs/9.x/configuration#debug-mode
https://laravel.com/docs/9.x/errors#configuration

How to retrieve draft grade from Google Classroom using api in php

I want to read draft grade marks from Google Classroom using API for a project. But I can't find out the draft grade. Already I've added some code to the quickstart.php file:
require __DIR__ . '/vendor/autoload.php';
// if (php_sapi_name() != 'cli') {
// throw new Exception('This application must be run on the command line.');
// }
/**
* Returns an authorized API client.
* #return Google_Client the authorized client object
*/
function getClient()
{
$client = new Google_Client();
$client->setApplicationName('Google Classroom API PHP Quickstart');
$client->setScopes(array(
Google_Service_Classroom::CLASSROOM_COURSES,
Google_Service_Classroom::CLASSROOM_STUDENT_SUBMISSIONS_STUDENTS_READONLY,
Google_Service_Classroom::CLASSROOM_ROSTERS)
);
$client->setAuthConfig(__DIR__ .'/credentials.json');
$client->setAccessType('offline');
$client->setPrompt('select_account consent');
// Load previously authorized token from a file, if it exists.
// The file token.json stores the user's access and refresh tokens, and is
// created automatically when the authorization flow completes for the first
// time.
$tokenPath = 'token.json';
if (file_exists($tokenPath)) {
$accessToken = json_decode(file_get_contents($tokenPath), true);
$client->setAccessToken($accessToken);
}
// If there is no previous token or it's expired.
if ($client->isAccessTokenExpired()) {
// Refresh the token if possible, else fetch a new one.
if ($client->getRefreshToken()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
} else {
// Request authorization from the user.
$authUrl = $client->createAuthUrl();
printf("Open the following link in your browser:\n%s\n", $authUrl);
print 'Enter verification code: ';
$authCode = trim(fgets(STDIN));
// Exchange authorization code for an access token.
$accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
$client->setAccessToken($accessToken);
// Check to see if there was an error.
if (array_key_exists('error', $accessToken)) {
throw new Exception(join(', ', $accessToken));
}
}
// Save the token to a file.
if (!file_exists(dirname($tokenPath))) {
mkdir(dirname($tokenPath), 0700, true);
}
file_put_contents($tokenPath, json_encode($client->getAccessToken()));
}
return $client;
}
$optParams = array(
'pageSize' => 1000
);
// Copyright 2021 Google LLC.
// SPDX-License-Identifier: Apache-2.0
// Get the API client and construct the service object.
$client = getClient();
$service = new Google_Service_Classroom($client);
// set these parameters:
// 328776504166 <- It is my course id
// 339429593407 <- It is my course work id
$courseId = "328776504166";
$courseWorkId = "339429593407";
$results = $service->courses_courseWork_studentSubmissions->listCoursesCourseWorkStudentSubmissions($courseId, $courseWorkId);
foreach ($results->studentSubmissions as $r => $submission) {
$student = $service->courses_students->get($courseId, $submission->userId);
$studentName = $student->profile->name->fullName;
print("<br>Student Name: ".$studentName . ": ");
print("<br>Draft Grade: ".$submission->draftGrade. "\n");
print("<br>Course Work Id: ".$submission->courseWorkId. "\n");
echo '<pre>';
print_r($submission);
}
Then when I run quickstart.php at localhost the following problems can be seen:
Fatal error: Uncaught Google_Service_Exception: { "error": { "code": 400, "message": "Precondition check failed.", "errors": [ { "message": "Precondition check failed.", "domain": "global", "reason": "failedPrecondition" } ], "status": "FAILED_PRECONDITION" } } in C:\xampp\htdocs\api\vendor\google\apiclient\src\Google\Http\REST.php:118 Stack trace: #0
I can't find my wrong. How to solve this problem? please give me some suggestions.
As stated in the documentation:
Students cannot see draft grades
This is why a student who intents to retrieve a draft grade will obtain a
403 - "Insufficient Permission" error.

Laravel "405 Method Not Allowed" on CCAvenue response return URL callback

I am adding CcAvenue gateway in laravel 5.3 on PHP 7.2, everything working fine till the payment page of CcAvenue, but after payment is done or payment canceled by the user, the return response URL is showing the following error
"Oops! An Error Occurred
The server returned a "405 Method Not Allowed".
Something is broken. Please let us know what you were doing when this error occurred. We will fix it as soon as possible. Sorry for any inconvenience caused."
My return URL is this: https:// www.domainname.com/booking/cancel/cc_checkout_gateway?c=f4b7d25d6e894a44725fff59adafcf82
Code in the Routes file
use Illuminate\Support\Facades\Route;
// Booking
Route::group(['prefix'=>config('booking.booking_route_prefix')],function(){
Route::post('/addToCart','BookingController#addToCart');
Route::post('/doCheckout','BookingController#doCheckout')->name('booking.doCheckout');
Route::get('/confirm/{gateway}','BookingController#confirmPayment');
Route::get('/cancel/{gateway}','BookingController#cancelPayment');
Route::get('/{code}','BookingController#detail');
Route::get('/{code}/checkout','BookingController#checkout');
Route::get('/{code}/check-status','BookingController#checkStatusCheckout');
//ical
Route::get('/export-ical/{type}/{id}','BookingController#exportIcal')->name('booking.admin.export-ical');
//inquiry
Route::post('/addEnquiry','BookingController#addEnquiry');
});
Route::group(['prefix'=>'gateway'],function(){
Route::get('/confirm/{gateway}','NormalCheckoutController#confirmPayment')->name('gateway.confirm');
Route::get('/cancel/{gateway}','NormalCheckoutController#cancelPayment')->name('gateway.cancel');
Route::get('/info','NormalCheckoutController#showInfo')->name('gateway.info');
});
Code in BookingController.php
public function cancelPayment(Request $request, $gateway)
{
$gateways = get_payment_gateways();
if (empty($gateways[$gateway]) or !class_exists($gateways[$gateway])) {
return $this->sendError(__("Payment gateway not found"));
}
$gatewayObj = new $gateways[$gateway]($gateway);
if (!$gatewayObj->isAvailable()) {
return $this->sendError(__("Payment gateway is not available"));
}
return $gatewayObj->cancelPayment($request);
}
Code in Gateway CcCheckoutGateway.php
public function cancelPayment(Request $request)
{
$c = $request->query('c');
$booking = Booking::where('code', $c)->first();
if (!empty($booking) and in_array($booking->status, [$booking::UNPAID])) {
$payment = $booking->payment;
if ($payment) {
$payment->status = 'cancel';
$payment->logs = \GuzzleHttp\json_encode([
'customer_cancel' => 1
]);
$payment->save();
// Refund without check status
$booking->tryRefundToWallet(false);
}
return redirect($booking->getDetailUrl())->with("error", __("You cancelled the payment"));
}
if (!empty($booking)) {
return redirect($booking->getDetailUrl());
} else {
return redirect(url('/'));
}
}
After too much R&D I found that my routes code is allowing method is GET & HEAD, but Ccavenue response URL is sending the response in POST method
I have tried every possible solution changed
Route::get('/cancel/{gateway}','BookingController#cancelPayment');
to
Route::post('/cancel/{gateway}','BookingController#cancelPayment');
and
Route::any('/cancel/{gateway}','BookingController#cancelPayment');
but after that it showing error 419: page expired
Please tell me how can I resolve the above issue.

Google sign-in for websites: read user's phone number

I want to obtain users' phone numbers via Google sign-in on my website. In JavaScript for the "sign in with Google" button, I'm including scope 'https://www.googleapis.com/auth/user.phonenumbers.read' for permission to read the user's phone number. Maybe instead of this scope, I need to use 'https://www.googleapis.com/auth/contacts.readonly'. In any case, how do I obtain a signed-in user's phone number in PHP or JavaScript? When a user clicks on the sign-in button then because of the scope Google does ask permission to share a phone number. In Google API Console -> Edit app registration -> Scopes, I've included this phone number scope. Also, I've enabled People API in the Google project. I've installed
composer require google/apiclient
From the front end i'm receiving id-token for the signed-in user. My PHP is:
<?php
require_once 'vendor/autoload.php';
$id_token = $_POST['idtoken'];
$client = new Google_Client(['client_id' => '349001386451-bpovja3t7soabdu3cbhnig12fqlr20o0.apps.googleusercontent.com']);
$payload = $client->verifyIdToken($id_token);
if ($payload) {
$userid = $payload['sub'];
echo "Userid: $userid";
} else {
echo "Invalid ID token";
}
( The above code has been edited from https://developers.google.com/identity/sign-in/web/backend-auth )
I'm a newbie to this. I've got my client-id, client-secret and user's id-token. I'm able to show the userid in the above code, how to display the phone number?
Edit: I downloaded my client_secret.json and tried another method:
index.php
<?php
require_once __DIR__.'/vendor/autoload.php';
session_start();
$client = new Google\Client();
$client->setAuthConfig('client_secret.json');
$client->setScopes(array('https://www.googleapis.com/auth/user.phonenumbers.read', 'https://www.googleapis.com/auth/contacts.readonly', 'profile'));
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
$client->setAccessToken($_SESSION['access_token']);
$service = new Google_Service_PeopleService( $client );
$optParams = ['personFields' => 'phoneNumbers'];
$profile = $service->people->get( 'people/me', $optParams );
var_export($profile);
var_export( $profile->getPhoneNumbers() );
} else {
$redirect_uri = 'https://' . $_SERVER['HTTP_HOST'] . '/testing/oauth2callback.php';
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
--
oauth2callback.php
<?php
require_once __DIR__.'/vendor/autoload.php';
session_start();
$client = new Google\Client();
$client->setAuthConfigFile('client_secret.json');
$client->setRedirectUri('https://' . $_SERVER['HTTP_HOST'] . '/testing/oauth2callback.php');
$client->addScope(Google_Service_PeopleService::USER_PHONENUMBERS_READ);
if (! isset($_GET['code'])) {
$auth_url = $client->createAuthUrl();
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
} else {
$client->authenticate($_GET['code']);
$_SESSION['access_token'] = $client->getAccessToken();
$redirect_uri = 'https://' . $_SERVER['HTTP_HOST'] . '/testing/';
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
But when I'm running index.php it's giving error:
"error": { "code": 403, "message": "The caller does not have
permission to request "people/me". Request requires one of the
following scopes: [profile]."
But I do have included the profile scope in index.php
The phone number used for password reset will not be possible access:
It has been determined that we will not return the account recovery
phone number. The account recovery phone number is only intended for
specific usage like recovery the account when locked out. In the
interest of protecting user privacy this will not be returned in the
3rd party API.
I'm successfully getting phone number using a new 3rd method as given here:
https://developers.google.com/people/api/rest/v1/people/get?apix=true&apix_params=%7B%22resourceName%22%3A%22people%2Fme%22%2C%22personFields%22%3A%22phoneNumbers%22%7D
I copied the JavaScript code given in this link, removed all scopes except one, replaced YOUR_API_KEY and YOUR_CLIENT_ID, ran it on my server, in Firefox and it worked!
<script src="https://apis.google.com/js/api.js"></script>
<script>
/**
* Sample JavaScript code for people.people.get
* See instructions for running APIs Explorer code samples locally:
* https://developers.google.com/explorer-help/guides/code_samples#javascript
*/
function authenticate() {
return gapi.auth2.getAuthInstance()
.signIn({scope: "https://www.googleapis.com/auth/user.phonenumbers.read"})
.then(function() { console.log("Sign-in successful"); },
function(err) { console.error("Error signing in", err); });
}
function loadClient() {
gapi.client.setApiKey("YOUR_API_KEY");
return gapi.client.load("https://people.googleapis.com/$discovery/rest?version=v1")
.then(function() { console.log("GAPI client loaded for API"); },
function(err) { console.error("Error loading GAPI client for API", err); });
}
// Make sure the client is loaded and sign-in is complete before calling this method.
function execute() {
return gapi.client.people.people.get({
"resourceName": "people/me",
"personFields": "phoneNumbers"
})
.then(function(response) {
// Handle the results here (response.result has the parsed body).
console.log("Response", response);
},
function(err) { console.error("Execute error", err); });
}
gapi.load("client:auth2", function() {
gapi.auth2.init({client_id: "YOUR_CLIENT_ID"});
});
</script>
<button onclick="authenticate().then(loadClient)">authorize and load</button>
<button onclick="execute()">execute</button>
But it only reads the phone number(s) added in Google account's "About me": https://myaccount.google.com/profile
And not the phone number of Google account which is used for password reset. I actually want this number but don't know whether possible.

Magento Ajax Login - Over SSL

I am working on an ajax login for magento and I have run into a small issue when dealing with ssl.
The request page that I am using to display my login view is a non-secure page. From this page, I am using ajax to post to a secure url (https://client.devserver/customer/account/ajaxLoginPost/). The json response I get back is correct, however when I refresh the page the user is not logged in.
I have tested this function on a non-secure site and it works as intended. It seems to only break when I add in the next layer of SSL.
Any help with this is greatly appreciated.
Here is the code from my controller.
public function ajaxLoginPostAction()
{
if ($this->_getSession()->isLoggedIn()) {
$this->_redirect('*/*/');
return;
}
$session = $this->_getSession();
if ($this->getRequest()->isPost()) {
$login = $this->getRequest()->getPost('login');
if (!empty($login['username']) && !empty($login['password'])) {
try {
$session->login($login['username'], $login['password']);
if ($session->getCustomer()->getIsJustConfirmed()) {
$this->_welcomeCustomer($session->getCustomer(), true);
}
$messages = array("isAuthed" => true);
} catch (Mage_Core_Exception $e) {
switch ($e->getCode()) {
case Mage_Customer_Model_Customer::EXCEPTION_INVALID_EMAIL_OR_PASSWORD:
$message = $e->getMessage();
break;
default:
$message = $e->getMessage();
}
$messages = array("isAuthed" => false, "userName" => $login['username'],"error"=> $message);
} catch (Exception $e) {
// Mage::logException($e); // PA DSS violation: this exception log can disclose customer password
}
} else {
$messages = array("isAuthed" => false, "userName" => $login['username'],"error"=>'Login and password are required.');
}
}
//$this->_loginPostRedirect();
$this->getResponse()->setBody(Mage::helper('core')->jsonEncode($messages));
}
There are effectively two cookies (and hence two sessions), one for the "http" connection and one for the "https".
You can either forward to a secure page after performing the login - which negates the need for an AJAX form - or return the SID in the JSON response and find a way to set the non-secure cookie with that value.
A third option is to leave the entire site as secured, it's extra work & cost for the server so not all businesses are willing to take that sensible precaution.

Resources