I need to retrieve a facebook page's list of posts (feed) using their javascript SDK, just like they explain in their docs: https://developers.facebook.com/docs/graph-api/reference/v2.4/page/feed
/* make the API call */
FB.api(
"/{page-id}/posts",
function (response) {
if (response && !response.error) {
/* handle the result */
}
}
);
I need it to be my website's "news section", so users should see it even if they are not connected to facebook.
The problem
Cool, but there is a problem... It returns: An access token is required to request this resource.
Holy cow... I'd like to get some access token for you #facebook, but my app doesn't make use of your authentication tools/plugins.
ANYWAY, I tried with FB.getLoginStatus(); but doesn't work, because the only way it can return an access_token is if the user is actually connected to the application. My users may not even be logged to facebook!
So, ¿How can I get an access_token to be stored into a variable, and later be used to get /{my-page}/posts?
I've already payed a look to this SO question, but it doesn't solves my problem, simply because there are no such "generic tokens".
I've also read https://developers.facebook.com/docs/facebook-login/access-tokens/ and that also relies on tokens generated through facebook login methods... So, can't I display a list of fb page's posts in my website, without being connected into facebook, hence an application?
ADD: My app is build with angularJS, I'm not dealing with server-side code. I shall rely purely on javascript methods.
You could either use an page or an app access token, but as you'd be using them on the client-side, neither of them are an option.
See
https://developers.facebook.com/docs/facebook-login/access-tokens#apptokens
https://developers.facebook.com/docs/facebook-login/access-tokens#pagetokens
Note that because this request uses your app secret, it must never be made in client-side code or in an app binary that could be decompiled. It is important that your app secret is never shared with anyone. Therefore, this API call should only be made using server-side code.
I'd strongly recommend to build a simple server-side script (PHP for example) to proxy the request to the Graph API. You could then call this via AJAX for example and load the posts asynchronously (and alse get rid of the FB JS SDK!). There is NO way to handle this in a secure manner if you don't want to use FB Login for all of your users (which also doesn't make much sense IMHO).
I think it's straightforward :)
Since pages' posts are always public, it only needs a valid access token to retrieve page posts.
Quoting what you've written:
So, ¿How can I get an access_token to be stored into a variable, and later be used to get /{my-page}/posts?
You only require an access token.
My suggestion would be;
- Generate an access token for yourself (no extra permission needed)
- request page-id/posts
This way you don't require other users to be connected to facebook, you can simply requests page-id/posts to retrieve posts with access token you generated for yourself.
I hope it solves your problem :D
TIP: As long as posts are public, you only require a valid access token, it doesn't need to be user or page specific.
Related
Not sure if the title summarises my question well.
Basically, I am trying to authenticate routes such as checking if user exists etc. I only want to allow
requests coming from my frontend application to be approved, but, since no user is signed in there is no token to send.
Api request -
mywebiste/checkUser/email
This route is unprotected on my backend because no user is logged in.
BUT I want to protect this route, in such a way that it's accessible only from the frontend.
Some ideas I came up with were adding specific headers tag from the frontend and check them on the backend, but that could be easily replicated, is there something more secure like using tokens etc.
I am using React and Node.js
Same origin policy is going to give you some basic protection, but basically if an API endpoint is exposed publicly, it's exposed publicly. If you don't want that route to be publicly accessible you need to add access control.
If you use that route to check if a user is already registered, you could, for example, merge it with the user registration route and send a different error code if the user already exists (which is not a great idea because it leaks which emails are registered on your system).
You can verify that a request was originated by a user (by authenticating him) but you cannot verify that a request comes from a particular client because of these two reasons :
If you include some API key in your client (web page or other), it's easily retrievable by everyone (the best thing you could do is offuscate it which makes things slightly harder but still possible)
If you send an API key over the network it's easily retrievable as well
The only thing you could do is prevent other web pages from calling your backend on behalf of the user, by using CORS (which is actually active by default if you dont specify an Access-Control-Allow-Origin header)
I ended up creating a kind of working solution, so basically, I create a new base64 string on my frontend and attach that to the header while making a request to the backend. The base64 string is different every minute, so even if the header is copied, it differs every minute and is combined with your secret key.
I have made a package so that people can use it if they want - https://github.com/dhiraj1site/ncrypter
You can use it like so
var ncrypter = require('ncrypter');
//use encode on your frontend with number of seconds and secret key
var encodedString = ncrypter.encrypt(2, 'mysecret1')
//use decode on your backend with same seconds and secret
var decodedString = ncrypter.decrypt(encodedString, 2, 'mysecret1');
console.log('permission granted -->', decodedString);
I've used code splitting to seprate restricted parts of my app into different chunks. This is working great so far, now I would like to ensure that the files themselves don't get served unless authenticated. I was thinking of using ngx_http_auth_request_module
http://nginx.org/en/docs/http/ngx_http_auth_request_module.html#auth_request
Which allows to send a sub-request before serving certain files. How can I ensure that certain headers are always send as part of the HTTP request when React wants to fetch the necessary chunks?
I have trouble understanding why you would need to prevent unauthenticated malicious users to have access to your static chunks.
Dynamic imports and code splitting are mainly used to reduce the bundle size for large applications as users won't necessarily need everything.
In order to secure your app you need to prevent users from seeing or tampering with data they do not have access to. This means the security lies with the API your app is talking to.
What I do:
Reject unauthenticated requests to the API
Keep a token client-side on authentication
Pass and check the token on all requests
Burn the token when obsolete and redirect to login
Notify, redirect users when they do not have access to some data or better not displaying content they do not have access to
I'm sure you already did what I wrote above, what I want to emphasize is that chunks are basically empty UI filled with data from the secured API.
Let's say I have bad intentions and I bypass client-side routing in order to have access to the restricted chunk. It will be an empty UI with secured API routes, I won't be able to do anything with it.
In case you have a very specific need, you might need to write a webpack plugin.
about the ensure request
One of webpack 's properties is that it can fetch only necessary chunks when loading pages.You can just use like require.ensurn to query chunks when necessary,so there is no need to ensure the certain headers.
ngx_http_auth_request_module
Ngx_http_auth_request_module and sub-request are always used to fetch web file in server.It's always used as backend authentication module.Here is the data flow direction in nginx.
When you download file, the download request will be passed to the server, then server return the override Http Request to Nginx,then Nginx will find the exact file.
The ngx_http_auth_request_module allows to send request to back server(like php .tomcat), and based on the request to pass or not, if pass, you will be able to fetch file in the back server.
nginx-----load speed
The nginx always fetch static file, like index.html.If have to validate the permission for every js/css everytime,then fetch it throw,thd loading speed for page will be very slow.
about how to authenticate
Since you have separated app.Here is a little suggestions.You can get the authenticated request by only import restricted parts in the authenticated file.And the webpack will automatically handle the rest.
fetch data from the server in the non-restricted part with information to authenticate like this:
http://.../api/auth?info=...
based on the infos in server to authenticate, and pass other infos like type back to the frontend
based on the type information to view .
if (this.props.type === "restrict"){
<restrict component/>
} else {
<non-restrict component/>
}
I'm trying to delete a comment using a Graph API call.
https://graph.facebook.com/[comment-id]?access_token=[access-token]&method=delete
However, in terms of access-token, I'm not sure which one to use? I have used my App's "User Access Token", "Page Access Token" and "App Token". It doesn't work for any of these.
[PS, my app has all permissions, and I have even submitted it for review]
I just wanted to know if it was even possible to delete a comment which was not posted by the application? (Because I see that Delete is only allowed for page access tokens).
So, please do let me know if it is possible to delete a comment from a user's posts. And if so, which access_token to provide.
The docs list all the neccessary Access Tokens and permissions:
https://developers.facebook.com/docs/graph-api/reference/v2.10/comment#deleting
I tried it with a user profile, it does not seem to be possible to post comments or delete them - no matter if was created by the App or manually:
Publishing comments through the API is only available for page access
tokens
For Pages, you need to use a Page Tokens with the neccessary permissions according to the docs.
It looks to me that you're doing an HTTP GET call and just putting &method=delete at the end. That's not how it works
You should do an HTTP DELETE call. So instead of doing something like $.get(...), you should do $.ajax with type: 'DELETE'
Also, make sure your token has publish_actions permission
I'm in a dead end, because I know that Javascript isn't made for synchronous work, and specially not AngularJS. However, I am in a situation where I am stuck needing it.
I have one main page on the domain "www" (with AngularJS), that calls "api" a lot. Some of the resources on "api" requires authentication, so it returns an 401, which in turn AngularJS picks up and displays a login-box when it sees.
The www-login supports a bunch of login methods and sends the password/oauth/whatever to the "api", which returns a token which the angular app stores in a cookie, and sets in $http.defaults.headers.common['Authorization'] so it can be used to authenticate furter requests to the api.
The same method is also used to get the username that belongs to the api-token.
This works perfectly and solves my design goals. But if the browser is going to an url that requires authentication, the 401 (and hence the login box pops-up). This is (I guess) because angular is not able to populate the Authorization field in the header before the 401 hits the browser..
Solutions?
Have an async=false request using jquery?
Close the login-box when we are done getting the data we want. The login box might flicker...
Store more meta-data about the login (ie, username) in cookies, so we dont haveto do get this information from the server when the app is loading.
??
Is there a better solution? This one time, for this one request, I want async=false in my Angular resource....
The solution I went for (which works perfectly) is to set $http.defaults.headers.common['Authorization'] = 'Token ' + old_api_token;, before the async request. And then overwrite it when the async request is done (if it have changed).
This is driving me totally crazy. I've set up an FB app and retrieved an access token by visiting: https://graph.facebook.com/oauth/access_token?grant_type=client_credentials&client_id=CLIENT_ID&client_secret=CLIENT_SECRET.
Now I want to grab a (publicly available) feed from this URL: https://graph.facebook.com/PAGE_OR_USER_ID/feed?access_token=ACCESS_TOKEN
It works fine when I try it with my own user ID or even when I try another random page but it DOESN'T work when I enter the PAGE_ID I need it to work with.
Here are some examples:
This works fine (a friend of mine's Facebook page):
https://graph.facebook.com/tatchit/feed?access_token=213451182120494|JgAwuCE74lh51t1pKMuRM2mz3GU&limit=10&offset=0
This also works fine (my own Facebook ID):
https://graph.facebook.com/al.dev.7/feed?access_token=213451182120494|JgAwuCE74lh51t1pKMuRM2mz3GU&limit=10&offset=0
This doesn't work (the client's Facebook page):
https://graph.facebook.com/142616539131188/feed?access_token=213451182120494|JgAwuCE74lh51t1pKMuRM2mz3GU&limit=10&offset=0
I don't get any errors but the result is empty.
If I try the Graph API Explorer it also works fine:
https://developers.facebook.com/tools/explorer/?method=GET&path=142616539131188%2Ffeed
But not if I enter my own access token. From what I understand the access tokens you get in the API Explorer are temporary so I don't want to use that.
How can this be?
Also. I've struggled to understand this whole access-token, client-id, app-id-business for ages now - is there a good tutorial where all this stuff is explained? I've never had this work without problems ever.
Thank you
You should be using user access token for all the above queries. App Access token is used when you want to do something like check the app insights so and so.
When the pages has age restrictions or something so, app token wont be able to get through, but since the user is already a member of the page, you can use the user access token to get the data.
Add : Quoting from the documentation,
Note that the **app access token** is for publishing purposes permitted by the publish_actions and publish_stream permissions. You will be **unable to retrieve information** about the status update post with the given ID using the app access token. Instead, you should use a **user access token** for such purposes.
Other Capabilities of an App Access Token
There is a limited set of information that can be retrieved from Facebook using an App Access Token.
Basic Profile Info of a User (ID, Name, Username, Gender)
A User’s Friends and their IDs
Permissions granted by the User to your App
Read : https://developers.facebook.com/docs/opengraph/using-app-tokens/
So you should be querying with the user_access token to access all the informations that you are looking for, not with an app access_token.
You are using an App Access token instead of a User Access token. Some of the pages you are viewing may have a country or age restriction set, so using an app token will not work.
See: http://developers.facebook.com/docs/concepts/login/access-tokens-and-types/