I am creating a REACT app that uses wordpress as a backend through the rest API. I am using the Simple-JWT-Login plugin to handle the register, login, authentication, and it works perfectly.
I want to block non-logged in users from accessing the /wp/v2/posts endpoint. I know I can do this by doing something like:
add_filter( 'rest_authentication_errors', function( $result ) {
if ( ! empty( $result ) ) {
return $result;
}
if ( ! is_user_logged_in() ) {
return new WP_Error( 'rest_not_logged_in', 'You are not currently logged in.', array( 'status' => 401 ) );
}
if ( ! current_user_can( 'edit_posts' ) ) {
return new WP_Error( 'rest_not_admin', 'You are not entitled to view that.', array( 'status' => 401 ) );
}
return $result;
});
However that blocks all endpoints, including ?rest_route=/simple-jwt-login/v1/auth and ?rest_route=/simple-jwt-login/v1/users which are the ones from the Simple-JWT-Login plugin used for registering and authenticating users. Therefore users end up in a catch 22 whereby they can't login unless they are already logged in!
Is there a way of modifying the above code to block just the wp/v2/posts/ endpoint, or, alternatively, of effectively whitelisting the registering and authenticating endpoints?
Many thanks for any ideas!
Have searched on here and elsewhere but can't find a solution.
You could always check for the url before showing the error with $_SERVER['REQUEST_URI'] but that might become a pain to add all your allowed urls in a if check.
I like to use apache_request_headers with preg_match to check for a Bearer Token and if the current request has the correct bearer token, show the results. Otherwise you would throw a error. I can't guarantee its 100% safe or the correct way to do it but it works pretty well for a super basic simple system.
Something like the below code might work for someone:
add_filter("rest_authentication_errors", function ($result) {
if (!empty($result)) {
return $result;
}
$headers = apache_request_headers();
$matches = array();
$currentToken = "PUT YOUR BEARER TOKEN HERE";
$pattern = $currentToken."/i";
preg_match('/Bearer '. $pattern, $headers['Authorization'], $matches);
if(isset($matches)){
$token = $matches[0];
if($token == 'Bearer ' . $currentToken){
return $result;
} else {
return new WP_Error( 'no_auth_found', 'You are not currently logged in.' , array( 'status' => 401));
}
}
});
Related
I am following Justin Slope's API Tutorial which was made in 2020.
This is the code that I pasted with some changes on the redirect URLs and using a site that is ok with the developer website.
$creds = array(
'app_id' => FACEBOOK_APP_ID,
'app_secret' => FACEBOOK_APP_SECRET,
'default_graph_version' => 'v3.2',
'persistent_data_handler' => 'session'
);
// create facebook object
$facebook = new Facebook\Facebook( $creds );
// helper
$helper = $facebook->getRedirectLoginHelper();
// oauth object
$oAuth2Client = $facebook->getOAuth2Client();
if ( isset( $_GET['code'] ) ) { // get access token
try {
$accessToken = $helper->getAccessToken();
} catch ( Facebook\Exceptions\FacebookResponseException $e ) { // graph error
echo 'Graph returned an error ' . $e->getMessage;
} catch ( Facebook\Exceptions\FacebookSDKException $e ) { // validation error
echo 'Facebook SDK returned an error ' . $e->getMessage;
}
if ( !$accessToken->isLongLived() ) { // exchange short for long
try {
$accessToken = $oAuth2Client->getLongLivedAccessToken( $accessToken );
} catch ( Facebook\Exceptions\FacebookSDKException $e ) {
echo 'Error getting long lived access token ' . $e->getMessage();
}
}
echo '<pre>';
var_dump( $accessToken );
$accessToken = (string) $accessToken;
echo '<h1>Long Lived Access Token</h1>';
print_r( $accessToken );
} else { // display login url
$permissions = [
'public_profile',
'instagram_basic',
'pages_show_list',
'instagram_manage_insights',
'instagram_manage_comments',
'manage_pages',
'ads_management',
'business_management',
'instagram_content_publish',
'pages_read_engagement'
];
$loginUrl = $helper->getLoginUrl( FACEBOOK_REDIRECT_URI, $permissions );
echo '<a href="' . $loginUrl . '">
Login With Facebook
</a>';
}
Whenever I try to use the code this is always the output been trying for about an hour by the time this is posted
I tried changing the graph versions and double-checking redirects and I am still stumped on this.
Had to remove almost all of the stuff on the permissions 'pages_show_list' was the only thing left since the data isn't supported on the standard access on the Facebook developer website, have to get a privacy URL to get full access to all the other permissions.
I try to have an app that can pause/resume my adset (accounts owned by myself).
I get no error message(or anything) output when requesting this
$adset = new AdSet($adsetid);
$adset->campaign_status = AdSet::STATUS_ACTIVE;
try{
$adset->updateSelf();
} catch (RequestException $e) {
$response = json_decode($e->getResponse()->getBody(), true);
var_dump($response);
}
But I see that the adset status did not change.
Now, I do see that the Marketing API, Settings section shows me that the API access Level is development and the app doesn't have Ads management standard access.
When I check permissions at App review > Permissions and features it shows 'Standard access' and 'ready to use'. (however not 'Active')
And at the same time my request count and error rate in the past 30 days are acceptable.
I don't understand what is missing to make it work. Can anyone help me out?
The code I have shown in my question was based on the code I copied from the Facebook marketing API documentation.
Strangely when I simulated my request using the Graph API Explorer and hit the "Get code" button it will suggest you a different code.
When I used that code instead of the code of the marketing API docs it did seem to work just as expected.
This code worked as opposed to the code from the docs:
$adsetid = "YOUR ADSET ID";
$access_token = "YOUR ACCESS TOKEN";
try {
$response = $fb->post(
'/'.$adsetid,
array (
'fields' => 'status',
'status' => 'ACTIVE'
),
$access_token
);
} catch(FacebookExceptionsFacebookResponseException $e) {
echo 'Graph returned an error: ' . $e->getMessage();
exit;
} catch(FacebookExceptionsFacebookSDKException $e) {
echo 'Facebook SDK returned an error: ' . $e->getMessage();
exit;
}
$graphNode = $response->getGraphNode();
In my javascript I have a click event that triggers an ajax call to the php page where I send my notification from. I chose to do it this way because the documentation advises against using your app secret in any client side code, and the notifications parameters requires an access token that you can only get using the app secret.
The problem I'm having is that even though I'm logged in, $facebook->getUser() is returning 0 in php, so the api call I make afterwards to send the notification wont work. My user is already logged in via the client side code, so how do I get the message to the php that they're logged in so the notification can be sent.
//JS
$.ajax({
url : "http://xxxxxo/bn/notification.php",
type : 'POST',
data: {notify: notify },
success : function (result) {
console.log(result);
},
error : function () {
alert("error sending notification");
}
});//closes ajax
//PHP
<?php
require_once(dirname(__FILE__).'/php-sdk/facebook.php') ;
$APPLICATION_ID = '1402xxxxx7';
$APPLICATION_SECRET = 'ce71d6bbxxxxx5f55a';
$fb_app_url = "http://apps.facebook.com/myAPP";
$config = array();
$config['appId'] = $APP_ID;
$config['secret'] = $APP_SECRET;
$config['cookie'] = true;
$facebook = new Facebook($config) or die('Error is here!');
$facebook = new Facebook(array(
'appId' => $APP_ID,
'secret' => $APP_SECRET,
'fileUpload' => true
));
$notify = $_REQUEST['notify'];
$userid = $facebook->getUser();
/*IF WE HAVE A LOGGED IN USER AND THE 'NOTIFY' REQUEST VALUE, THEN SEND THE NOTIFICATION.
BUT MY USER ID IS 0. HOW DO I GET PHP TO RECOGNIZE ME AS LOGGED IN WITHOUT HAVING TO FORCE MY USER TO LOG IN VIA PHP AFTER THEY'VE ALREADY LOGGED IN CLIENT SIDE?*/
if($userid && $notify){
$token_url ="https://graph.facebook.com/oauth/access_token?" .
"client_id=" . $APP_ID .
"&client_secret=" . $APP_SECRET .
"&grant_type=client_credentials";
$app_token = file_get_contents($token_url);
$app_token = str_replace("access_token=", "", $app_token);
$data = array(
'href'=> 'https://apps.facebook.com/thebringernetwork/',
'access_token'=> $app_token,
'template'=> 'test'
);
$sendnotification = $facebook->api('/1622649653/notifications', 'post', $data);
}else{
//handle error
}
?>
The first thing I noticed is that you define your app id as $APPLICATION_ID but use it as $APP_ID (and the same goes for your app secret). But since you didn't mention any errors and $facebook->getUser(); executes I'm guessing this is just a bad copy-paste.
Now for the sake of answering this question I'm going to presume that you are using the latest versions of both JS and PHP SDKs. These use oauth 2.0 and change the way you pass the login information from JS to PHP.
According to Facebook Developer Blog removing $config['cookie'] = true; and setting oauth to true in your JS configuration should work. Just make sure to refresh the site after the login.
The solution I've found in my own project is to disable cookies altogether and simply pass the access token to my PHP script.
In your JS call your PHP script like this (make sure to call this after the JS login!):
$.ajax({
url : "http://xxxxxo/bn/notification.php",
type : 'POST',
data: {
notify: notify,
token: FB.getAuthResponse()['accessToken'] // add your access token
},
success : function (result) {
console.log(result);
},
error : function () {
alert("error sending notification");
}
});
And in your PHP script add this after creating the FB object.
$facebook->setAccessToken($_POST['token']); // set the users access token
Doing things this way will also get rid of any need to refresh the website after the login.
Yes, this is a common problem when using the PHP SDK in combination with AJAX:
When you make an AJAX request, the PHP SDK deletes the cookies where the authorization information are stored, and then the next call to getUser will just return 0, because this method tries to find the current user id in those cookies – apparently there is something in the OAuth 2.0 spec that demands this behavior to prevent some sort of click-jacking attack.
But the info will still be stored in the session, so you can read the user id (and the user access token, should you need it) from there:
$user_id = $_SESSION['fb_YourAppIdHere_user_id'];
$user_access_token = $_SESSION['fb_YourAppIdHere_access_token'];
Replace YourAppIdHere with your app id (so it becomes fb_1234567890_user_id resp. fb_1234567890_access_token) to get the correct names of those session keys.
I'm trying to retrieve users events using the facebook php sdk, but i'm stuck, the api return an empty array
$user = $me['id'];
$fql = "SELECT eid, name, start_time, end_time
FROM event
WHERE eid IN (SELECT eid
FROM event_member
WHERE uid = 1552544515)
ORDER BY start_time LIMIT 5";
$params = array(
'method' => 'fql.query',
'query' => $fql,
);
try {
$result = $facebook->api($params);
} catch (FacebookApiException $e) {
echo $e->getMessage();
}
thanks in advance.
If this is returning nothing, the most likely reason is that your user hasn't granted the user_events Permission during the Authentication flow.
Looking at your comments above, you may have added user_events to the permissions granted when a user goes through the Authenticated Referrals flow or via App Center, but regular users accessing the app directly need to go through one of the authentication flows from the document above, you're probably not doing this
I'm trying to add a tab to a fanpage using the graph api/PHP SDK and I'm receiving an error :
(#210) Subject must be a page I've tried using both the user access_token AND the page access_token but neither work. I've tried using the page id of numerous accounts and still no go. Here is my code:
<?php
$path="/PAGE_ID/tabs/";
$access_token="ACCESS_TOKEN";
$params = array(
'app_id' => "APP_ID",
'access_token' => $access_token
);
try{
$install = $facebook->api($path, "POST", $params);
}catch (FacebookApiException $o){
print_r($o);
}
?>
And here is the error I get:
FacebookApiException Object
(
[result:protected] => Array
(
[error] => Array
(
[message] => (#210) Subject must be a page.
[type] => OAuthException
)
)
[message:protected] => (#210) Subject must be a page.
[string:Exception:private] =>
[code:protected] => 0
Thanks for any help you can provide!
If you are not limited to using the API to add your application to your page then you can follow the instructions provided by Facebook at this link :
https://developers.facebook.com/docs/reference/dialogs/add_to_page/
Essentially you can use a dialog ( see the link above ) or this direct URL to add tab apps to your page :
https://www.facebook.com/dialog/pagetab?app_id=YOUR_APP_ID&display=popup&next=YOUR_URL
Dont forget to substitute APP_ID for your app id and next for a different URL
API Call is atm bugged: https://developers.connect.facebook.com/bugs/149252845187252?browse=search_4f31da351c4870e34879109
But here is a solution for JS: OAuthException "(#210) Subject must be a page." - just do not use the library and do your own call.
I did it with PHP:
<?php
$url = 'https://graph.facebook.com/<PAGE ID>/tabs?app_id=<APP ID>&method=POST&access_token=<PAGE ACCESS TOKEN>&callback=test';
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
$result = curl_exec($ch);
curl_close($ch);
echo $result;
?>
Echo value should be something like "test(true)".