Facebook Javascript API: '/me/albums' not working for other users - javascript

I am using the '/me/albums' for my website app in JavaScript. It returns the correct array when I use the app but not for other users.
Also, I have put the { scope: 'user_photos' } in FB.login(), but it doesn't ask the user for Photos permission when they log in.
For getting access_token, I'm using this:
accessToken = response.authResponse.accessToken;

Most permissions need to get reviewed before the can be used by everyone. Without review, they only work for users with a role in the App.
There should actually be a warning text whenever you try to login as an App Admin or Developer.
Official docs: https://developers.facebook.com/docs/facebook-login/review

Related

React-Firebase Authentication

I am having a react application with firebase as authentication. My authentication code is below
await firebase.auth().onAuthStateChanged((user) => {
if (user) {
props.setUser(user); //setting the user if login/register happens
history.push(`/admin/dashboard`);
console.log("user",user)
} else {
props.setUser(null); //blocks the user to get into the app if he/she is not logged in
history.push("/");
}
});
So, when user logs in..he will be navigated to /admin/dashboard. suppose when am in /admin/home and when i refresh the page, it goes again to admin/dashboard which shouldn't happen. so I tried
history.push(${props.location.pathname}); it works correctly after the refresh, it stays on the same page when the application is logged in. but when I restart the server again when I try to log in, it says no redirect url is specified. Got stuck on this for a long time.. Any help is welcome.Thanks
What your code does is check if the user is logged in and only let the user access the data if so.
You should do that in the fireabse rules (= serverside) as this is way more secure.
You didn't provide the kind of FirebaseDB you are using. So assuming you use the Realtime Database here are some according rules:
{
“rules”: {
“.read”: “auth != null”,
“.write”: “auth != null”
}
}
You should maybe check the rules before deploying your app, because now every authenticated user can change/add/delete data, but you get the point. This does exactly what you want so you won't even need to perform a check in your ReactJS App. Firebase will automatically deny unauthenticated users the access to the database.
Btw: You should try to implement security relevant things in the Firebase Rules. Ideally you want your rules to be written in a way that you don't need to perform any validation inside your ReactJS app. Firebase rules can get quite complex. I experienced that myself when writing a chat app with chatrooms and everything. But it is definitly worth the effort if your app is more secure after.

Single flow: sign user in via Google oAuth AND grant offline/server access?

I'm trying to implement Google sign-in and API access for a web app with a Node.js back end. Google's docs provide two options using a combo of platform.js client-side and google-auth-library server-side:
Google Sign-In with back-end auth, via which users can log into my app using their Google account. (auth2.signIn() on the client and verifyIdToken() on the server.)
Google Sign-in for server-side apps, via which I can authorize the server to connect to Google directly on behalf of my users. (auth2.grantOfflineAccess() on the client, which returns a code I can pass to getToken() on the server.)
I need both: I want to authenticate users via Google sign-in; and, I want to set up server auth so it can also work on behalf of the user.
I can't figure out how to do this with a single authentication flow. The closest I can get is to do the two in sequence: authenticate the user first with signIn(), and then (as needed), do a second pass via grantOfflineAccess(). This is problematic:
The user now has to go through two authentications back to back, which is awkward and makes it look like there's something broken with my app.
In order to avoid running afoul of popup blockers, I can't give them those two flows on top of each other; I have to do the first authentication, then supply a button to start the second authentication. This is super-awkward because now I have to explain why the first one wasn't enough.
Ideally there's some variant of signIn() that adds the offline access into the initial authentication flow and returns the code along with the usual tokens, but I'm not seeing anything. Help?
(Edit: Some advice I received elsewhere is to implement only flow #2, then use a secure cookie store some sort of user identifier that I check against the user account with each request. I can see that this would work functionally, but it basically means I'm rolling my own login system, which would seem to increase the chance I introduce bugs in a critical system.)
To add an API to an existing Google Sign-In integration the best option is to implement incremental authorization. For this, you need to use both google-auth-library and googleapis, so that users can have this workflow:
Authenticate with Google Sign-In.
Authorize your application to use their information to integrate it with a Google API. For instance, Google Calendar. 
For this, your client-side JavaScript for authentication might require some changes to request
offline access:
$('#signinButton').click(function() {
auth2.grantOfflineAccess().then(signInCallback);
});
In the response, you will have a JSON object with an authorization code:
{"code":"4/yU4cQZTMnnMtetyFcIWNItG32eKxxxgXXX-Z4yyJJJo.4qHskT-UtugceFc0ZRONyF4z7U4UmAI"}
After this, you can use the one-time code to exchange it for an access token and refresh token.
Here are some workflow details:
The code is your one-time code that your server can exchange for its own access token and refresh token. You can only obtain a refresh token after the user has been presented an authorization dialog requesting offline access. If you've specified the select-account prompt in the OfflineAccessOptions [...], you must store the refresh token that you retrieve for later use because subsequent exchanges will return null for the refresh token
Therefore, you should use google-auth-library to complete this workflow in the back-end. For this,
you'll use the authentication code to get a refresh token. However, as this is an offline workflow,
you also need to verify the integrity of the provided code as the documentation explains:
If you use Google Sign-In with an app or site that communicates with a backend server, you might need to identify the currently signed-in user on the server. To do so securely, after a user successfully signs in, send the user's ID token to your server using HTTPS. Then, on the server, verify the integrity of the ID token and use the user information contained in the token
The final function to get the refresh token that you should persist in your database might look like
this:
const { OAuth2Client } = require('google-auth-library');
/**
* Create a new OAuth2Client, and go through the OAuth2 content
* workflow. Return the refresh token.
*/
function getRefreshToken(code, scope) {
return new Promise((resolve, reject) => {
// Create an oAuth client to authorize the API call. Secrets should be
// downloaded from the Google Developers Console.
const oAuth2Client = new OAuth2Client(
YOUR_CLIENT_ID,
YOUR_CLIENT_SECRET,
YOUR_REDIRECT_URL
);
// Generate the url that will be used for the consent dialog.
await oAuth2Client.generateAuthUrl({
access_type: 'offline',
scope,
});
// Verify the integrity of the idToken through the authentication
// code and use the user information contained in the token
const { tokens } = await client.getToken(code);
const ticket = await client.verifyIdToken({
idToken: tokens.id_token!,
audience: keys.web.client_secret,
});
idInfo = ticket.getPayload();
return tokens.refresh_token;
})
}
At this point, we've refactored the authentication workflow to support Google APIs. However, you haven't asked the user to authorize it yet. Since you also need to grant offline access, you should request additional permissions through your client-side application. Keep in mind that you already need an active session.
const googleOauth = gapi.auth2.getAuthInstance();
const newScope = "https://www.googleapis.com/auth/calendar"
googleOauth = auth2.currentUser.get();
googleOauth.grantOfflineAccess({ scope: newScope }).then(
function(success){
console.log(JSON.stringify({ message: "success", value: success }));
},
function(fail){
alert(JSON.stringify({message: "fail", value: fail}));
});
You're done with the front-end changes and you're only missing one step. To create a Google API's client in the back-end with the googleapis library, you need to use the refresh token from the previous step.
For a complete workflow with a Node.js back-end, you might find my gist helpful.
While authentication (sign in), you need to add "offline" access type (by default online) , so you will get a refresh token which you can use to get access token later without further user consent/authentication. You don't need to grant offline later, but only during signing in by adding the offline access_type. I don't know about platform.js but used "passport" npm module . I have also used "googleapis" npm module/library, this is official by Google.
https://developers.google.com/identity/protocols/oauth2/web-server
https://github.com/googleapis/google-api-nodejs-client
Check this:
https://github.com/googleapis/google-api-nodejs-client#generating-an-authentication-url
EDIT: You have a server side & you need to work on behalf of the user. You also want to use Google for signing in. You just need #2 Google Sign-in for server-side apps , why are you considering both #1 & #2 options.
I can think of #2 as the proper way based on your requirements. If you just want to signin, use basic scope such as email & profile (openid connect) to identify the user. And if you want user delegated permission (such as you want to automatically create an event in users calendar), just add the offline access_type during sign in. You can use only signing in for registered users & offline_access for new users.
Above is a single authentication flow.

Is it possible to post to chat.postMessage as any user in a Slack team?

I'm building a Slack integration that is intended to modify some text and then post it to a Slack channel as though the user who triggered the command had said it.
e.g. /makeFace disapproval
#Ben 3:45pm
ಠ_ಠ
I ask for the client permission scope, which adds the chat:write:user permission. But when I hit the chat.postMessage endpoint, it only seems to allow you to post as the user who added the integration because the token it returns seems to be individuated for that user.
I know that giphy, for instance, sends its gif messages as though you are the originator, but I can't find out how they manage it. Is there any documentation for sending messages as other members of the team?
There are 2 ways to achieve this:
A. Overwriting username and icon
When you send a message with chat.postMessage it is possible to set a user name with the property username. The message will then appear as being send by that user (same for icon with icon_url).
However, this is not meant to impersonate real users, so even if you use the same username and icon as the real user the message will have the app tag, so that they can be distinguished from a real user.
Here is an example how it looks like (from a gamer Slack about flying and killing space ships):
But depending on what your requirements are that might work for you.
If you want to use it make sure to also set the as_user property to false (yes, really) and it will not work with a bot token, only with a user token.
See here for more details on how it works.
This also works for the legacy version of Incoming Webhooks, not with the current version of incoming webhooks though. (You can still get the legacy version, see this answer)
B. Having the user's token
Another approach is to always use the token from the respective user for sending the message. In combination with as_user = true messages sent by your app will look exactly as if they would come from the respective user (no APP tag).
To make that happen your app would need to collect tokens from all users on your workspace and store them for later use. This can be done by asking every user to install your app (called adding a "configuration") through the Oauth process (same you use to install your app to a workspace), which allows your app to collect and store those tokens for later use.
Update: This doesn't work. It impersonates the user who installed the app, so it merely seems to work... until another user tries to use it (and they end up impersonating you).
Go to your App's management page. Select "OAuth & Permissions".
Add the chat.write OAuth Scope to your app as a User Token Scope, not a Bot Token scope.
Take note of your User OAuth Token at the top of this page (not your But User OAuth Token).
Call chat.postMessage with
username = user id of the user you'd like to post on behalf of
token = the token from step 3. above
The resulting post will be 100% impersonated. Not just the name and icon as mentioned in other answers, but it'll 100% function as if it came from the user.
I hope this will help those who are still facing this issue.
First give the chat:write and chat:write.customize scope to your bot. The scope chat:write.customize Send messages as #your_slack_app with a customized username and avatar
From "OAuth & Permissions" settings get the bot OAuth token or even bot access token (both will work).
Then set the arguments like the following.
username to specify the username for the published message.
icon_url to specify a URL to an image to use as the profile photo alongside the message.
icon_emoji to specify an emoji (using colon shortcodes, eg. :white_check_mark:) to use as the profile photo alongside the message.
You can visit the docs from here

facebook login permissions not displayed for some users

I'm using Facebook js sdk, requesting the 'user_birthday' permission.
FB.getLoginStatus(function(response) {
if (response.status === 'connected') {
_fbLoginCallBack(response);
} else {
var permissions = {
scope : 'email,user_birthday'
};
FB.login(responseCallback, permissions);
}
});
I have made the app and all its live features available to the general public.
The code works If I am logged with the same account I created the app with, but when try using different account, it doesn't display the permissions, and the returned JSON is missing the email and the birthday fields
What's happening ?
1. Login Review
You might need to do a Login review.
Review is not required to ask for the three basic permissions: public_profile, user_friends and email. In order to use Facebook Login in your app and access additional elements of a person's Facebook profile, you will need to submit your app for review. If your app is not approved or you don't submit for review, people will not be able to use Facebook Login in your app.
https://developers.facebook.com/docs/facebook-login/review
2. Make app live
You need to make the app and all its live features available to the general public. This can be done by making the app live by going to https://developers.facebook.com, select Apps --> Your App Name --> 'Status & Review'.

Explain the Facebook access_token

This whole Facebook access_token thing is driving me nuts. All I want to do is fetch a user's public Facebook posts.
It used to work by simply doing:
$.getJSON('http://graph.facebook.com/USERNAME/posts?limit=LIMIT&callback=?', function (posts) {
// Posts available in "posts" variable
});
But now I get the "access_token required" error.
Trust me; I've checked the docs, Googled all over and checked similar questions on SO but I'm really hoping there's a more straight forward way of doing this than what I've seen.
Do you really have to create a Facebook App (I don't even have an account), make the user "accept" the app and login etc for this to work?
With Twitter it's just as easy as it used to be with Facebook.
You really have to create a Facebook App (You need to have an account), make the user "accept" the app and login etc for this to work.
However you can search public posts of user (not a specific user) by facebook's public search api.
e.g.
https://graph.facebook.com/search?q=hello&type=post
This will search all posts with hello keyword in it.
Reference ( you need to have facebook account to see this page )
http://developers.facebook.com/docs/reference/api/
Edit (after seeing comments):
If you want to access public posts of your own page. You can pull it without any login from user (but you will need an access_token)
Generate an offline access_token from here,
http://developers.facebook.com/tools/explorer.
Then you can use that token to pull data . Thus no need of logging on by user.
https://graph.facebook.com/wesellwine/posts?access_token=<access_token from graph api explorer>

Categories

Resources