I have a Facebook canvas app.
I need an access token, the user authorizes the app and the apps main page works fine, but not the other pages.
When I click one link in my app that redirects to subpage, it need authorization again.
my controller code (Yii) is:
protected function beforeAction($action)
{
session_start();
$this->fb = new Facebook\Facebook([
'app_id' => '',
'app_secret' => '',
'default_graph_version' => 'v2.2',
]);
$this->checkFbLogin();
$this->getFbUser();
if (!Yii::app()->player->uid) {
$this->registerFbUser(); //connect facebook uid with game uid
}
return true;
}
private function checkFbLogin()
{
$helper = $this->fb->getCanvasHelper();
try {
$accessToken = $helper->getAccessToken();
} catch(Facebook\Exceptions\FacebookResponseException $e) {
// When Graph returns an error
echo 'Graph returned an error: ' . $e->getMessage();
exit;
} catch(Facebook\Exceptions\FacebookSDKException $e) {
// When validation fails or other local issues
echo 'Facebook SDK returned an error: ' . $e->getMessage();
exit;
}
if (! isset($accessToken)) {
//echo 'No OAuth data could be obtained from the signed request. User has not authorized your app yet.';
echo '<script>top.window.location="' . $this->getLoginUrl() . '"; </script>';
exit;
}
$this->accessToken = $accessToken;
}
private function getLoginUrl()
{
$helper = $this->fb->getRedirectLoginHelper();
$permissions = []; // optional
$loginUrl = $helper->getLoginUrl('https://apps.facebook.com/my-game/', $permissions);
return $loginUrl;
}
I can't see what is the problem. I can't find anything that can help.
When I click a link in the app, I don't get my accessToken in the checkFbLogin() function.
I am using the PHP SDK v5.0.0 installed with composer.
Related
i am working on web site with razor pages. part of the site should be accessed only by registred users. decided to go with firebase authentification (now with login and password ).
created everything necessary in firebase.
created backend code for user registration - works well.
created area which requires authorisation
services.AddRazorPages(options =>
{
options.Conventions.AuthorizeAreaFolder("User", "/");
})
added jwt middleware
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
added code to login page to call firebase to get token
function login()
{
firebase.auth().signInWithEmailAndPassword(email, password)
.then((userCredential) => {
// Signed in
var user = userCredential.user;
// ...
alert("signed");
})
.catch((error) => {
var errorCode = error.code;
var errorMessage = error.message;
alert(errorMessage);
});
}
got token from firebase.
if i'd call service next, i'd simply put token in "bearer" header.
tried to find how to add header to current browser for future requests and failed.
as i understand, i need this token to be added to auth header ? how ? :)
feeling dumb ;( tried to google, but most samples are for using this token later with api calls.
or i am going in the wrong direction?
tia
ish
well. it seems that it is not possible to add bearer from js, so i switched to cookies
in startup.cs use cookies
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
context.Token = context.Request.Cookies["bearer"];
return Task.CompletedTask;
}
};
code to login with firebase, put token into the cookie and redirect
function login() {
firebase.auth().signInWithEmailAndPassword(email, password)
.then((userCredential) => {
// Signed in
var user = userCredential.user;
firebase.auth().currentUser.getIdToken(true).then(function (idToken)
{
document.cookie = "bearer" + "=" + idToken;
window.location.href = "/user/index";
}).catch(function (error) {
// Handle error
});
alert("signed");
})
.catch((error) => {
var errorCode = error.code;
var errorMessage = error.message;
alert(errorMessage);
});
}
or the same with firebaseUI
function login1()
{
ui.start('#firebaseui-auth-container', {
signInSuccessUrl: '/User/index',
signInOptions: [
{
provider: firebase.auth.EmailAuthProvider.PROVIDER_ID,
requireDisplayName: false
}
],
callbacks:
{
signInSuccessWithAuthResult: function (authResult, redirectUrl)
{
var user = authResult.user;
firebase.auth().currentUser.getIdToken(true).then(function (idToken) {
document.cookie = "bearer" + "=" + idToken;
}).catch(function (error) {
// Handle error
});
return true;
}
}
});
}
I try to call internal JWT API for check token(expired or not..) and I stored token in browser session
public function index(){
$check = $this->check_login();
if($check != 1){
return Redirect::to('login');
}
return view('main_pages.home');
}
function check_login(){
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
$token = $_SESSION['token'];
$request = Request::create('/api/user', 'POST');
$request->headers->set('Accept', 'application/json');
$request->headers->set('Authorization', 'Bearer '.$token);
$response = app()->handle($request);
$res = json_decode($response->getContent()); // convert to json object
return $res->status;
}
when I got $res->status = 0; it's redirect to localhost/login (without port) this issuse come from when I called app()->handle($resquest)
So how can I redirect('login') after I accessed to internal JWT API by app()->handle($resquest)
or have another way to access to internal JWT API and then redirect some route
Below code used for the edit google spreadsheet, but we are getting issue related to the access token, let me know if anyone has a solution for this issue. For the Outh client id we have flow these instructions:
https://developers.google.com/analytics/devguides/reporting/core/v3/quickstart/web-php
[29-Sep-2019 04:10:36 UTC] PHP Fatal error: Uncaught InvalidArgumentException: Invalid token format in /home/help4dl9/public_html/doamin.com/wp-content/themes/twentynineteen/google-sheet/vendor/google/apiclient/src/Google/Client.php:423
Here getClient function:
function getClient()
{
$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
$client = new Google_Client();
$client->setApplicationName('APP NAME');
$client->setScopes( 'https://www.googleapis.com/auth/spreadsheets' );
$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 = __DIR__ . '/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());
$authObj = $client->getAccessToken();
if(array_key_exists("access_token",$authObj)) {
update_field( 'authentication_code', $authObj['access_token'],'option' ); // Save Token in Theme Option
}
} else {
// Request authorization from the user.
$authCode = get_field('authentication_code','option');
// 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;
}```
Follow instead the instructions of PHP Quickstarts for Sheets API without $redirect_uri and get_field:
<?php
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 Sheets API PHP Quickstart');
$client->setScopes(Google_Service_Sheets::SPREADSHEETS_READONLY);
$client->setAuthConfig('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;
}
Make sure sure to enable the sheets API and paste the credentials.json file into the right folder, as explained in the quickstart. Also, whenever you change the required scopes, you need to manually delete the token.json file from your drive.
I have already written an API call for check authentication using Laravel. I need to move that controller to Lumen for use it as micro service.
This is my controller in Laravel.
public function byCredantial(Request $request)
{
$user = [
'email' => $request->input('email'),
'password' => $request->input('password')
];
if (Auth::attempt($user)) {
$response = $this->getSuccess(Auth::user()->id);
return response()->json($response, 200);
} else {
$response = $this->getError($user);
return response()->json($response, 401);
}
}
Lumen doc is not provide how to do such authentication. They has not function for check creadential is correct. How can i do this in Lumen. Is this possible?
You can do this in Lumen. Facades are disabled by default (if you want to enable it you can see the instructions in the documentation), but I would not recommend enabling the facades as the add additional overhead to your application. Instead, I would modify your function to call app('auth'). This will return the class that the Auth facade proxies without loading all the other facades.
public function byCredantial(Request $request)
{
$user = [
'email' => $request->input('email'),
'password' => $request->input('password')
];
$auth = app('auth');
if ($auth->attempt($user)) {
$response = $this->getSuccess($auth->user()->id);
return response()->json($response, 200);
} else {
$response = $this->getError($user);
return response()->json($response, 401);
}
}
Also, I would recommend reading the authentication documentation and placing the bulk of this code in the AuthServiceProvider.
I'm tring to login via my own service. This is what I have now:
manifest.json
"background": {
"scripts": ["background.js"]
}
background.js
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.create({
url: 'index.html'
});
});
index.html is where all the extension's logic resides. Here I have a function that starts authentication process:
function goLogin(callback)
{
var redirectUrl = chrome.identity.getRedirectURL('receiveToken');
chrome.identity.launchWebAuthFlow({
url: 'http://todolist.dev/app_dev.php/login?response_type=token&redirect_url=' + redirectUrl,
interactive: true
}, function(redirectUrl) {
if (!redirectUrl) {
return;
}
// Get an access token from the url and save it in localStorage
var queryString = decodeURIComponent(redirectUrl.substr(redirectUrl.indexOf('?') + 1));
var params = queryString.split('&');
var accessToken = null;
for (var i = 0; i < params.length; i++) {
params[i] = params[i].split('=');
if (params[i][0] == 'access_token') {
accessToken = params[i][1];
break;
}
}
localStorage.setItem('accessToken', accessToken);
callback();
});
}
The problem is that the popup with the service's login page sometimes doesn't open or opens and closes automatically with the response that the user didn't approve access. Sometimes when the popup opens and I try to login with wrong credentials several times, the popup closes automatically as well (with the same "you didn't approve access" response). In the backend I don't have any restrictions to a number of login attempts.
In the backend I have a FOSUserBundle with overridden AuthenticationSuccessHandler (it does what the default success handler does + returns an access token).