mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Facebook is making a change on April 30th: all users of the previous unversioned Facebook API will automatically start using the 2.0 API, and the 1.0 API will be unavailable. By upgrading your Meteor to include this commit, you will be able to start adapting your app to the post-1.0 world now rather than next month. Full information about the changes to Facebook's APIs can be found at https://developers.facebook.com/docs/apps/upgrading If you only use Facebook integration for login via accounts-facebook, and don't use users' access tokens to access the Facebook API on their behalf, then the only changes you are likely to observe are: - The `id` returned by Facebook for users who had not previously used your app will be an "app-scoped ID". You cannot use these to directly correlate users between multiple apps (without using the Business Mapping API). This does not affect users who have already logged in to your app, so they will continue to be able to access your app. - Meteor asks for the `email` permission by default, and copies the `email` field from the `/me` object into the `serviceData.facebook` field on `Meteor.user()`, along with other fields which only require the `public_profile` permission. With 2.0, users can decline to grant all permissions other than `public_profile`, which means that you might not get their `email` address. You can use the `/me/permissions` API to tell if permissions were declined. Additionally, if you are accessing other Facebook APIs using the `access_token` returned via login, you should be aware that some permissions have changed in Facebook Graph API 2.0 and newer. Most notably, many operations involving friends need permissions such as `user_friends` to be explicitly requested now. Users can decline any permission (other than `public_profile`). Apps which need permissions other than `public_profile`, `email`, and `user_friends` may need to pass through a review stage before being fully activated. To change your app to request new permissions such as `user_friends`, specify the `requestPermissions` option to `Meteor.loginWithFacebook` (if you implemented your own login UI) or to `Accounts.ui.config` (if you are using the `accounts-ui` package). Note that while Meteor will now always use the v2.2 API to fetch the access token, it does appear that the access token can still be used to access pre-v2.2 APIs. For example, you can still use the access token to run FQL queries, even though FQL was removed in API v2.1. Fixes #3123.
101 lines
3.0 KiB
JavaScript
101 lines
3.0 KiB
JavaScript
Facebook = {};
|
|
|
|
var querystring = Npm.require('querystring');
|
|
|
|
|
|
OAuth.registerService('facebook', 2, null, function(query) {
|
|
|
|
var response = getTokenResponse(query);
|
|
var accessToken = response.accessToken;
|
|
var identity = getIdentity(accessToken);
|
|
|
|
var serviceData = {
|
|
accessToken: accessToken,
|
|
expiresAt: (+new Date) + (1000 * response.expiresIn)
|
|
};
|
|
|
|
// include all fields from facebook
|
|
// http://developers.facebook.com/docs/reference/login/public-profile-and-friend-list/
|
|
var whitelisted = ['id', 'email', 'name', 'first_name',
|
|
'last_name', 'link', 'username', 'gender', 'locale', 'age_range'];
|
|
|
|
var fields = _.pick(identity, whitelisted);
|
|
_.extend(serviceData, fields);
|
|
|
|
return {
|
|
serviceData: serviceData,
|
|
options: {profile: {name: identity.name}}
|
|
};
|
|
});
|
|
|
|
// checks whether a string parses as JSON
|
|
var isJSON = function (str) {
|
|
try {
|
|
JSON.parse(str);
|
|
return true;
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
// returns an object containing:
|
|
// - accessToken
|
|
// - expiresIn: lifetime of token in seconds
|
|
var getTokenResponse = function (query) {
|
|
var config = ServiceConfiguration.configurations.findOne({service: 'facebook'});
|
|
if (!config)
|
|
throw new ServiceConfiguration.ConfigError();
|
|
|
|
var responseContent;
|
|
try {
|
|
// Request an access token
|
|
responseContent = HTTP.get(
|
|
"https://graph.facebook.com/v2.2/oauth/access_token", {
|
|
params: {
|
|
client_id: config.appId,
|
|
redirect_uri: OAuth._redirectUri('facebook', config),
|
|
client_secret: OAuth.openSecret(config.secret),
|
|
code: query.code
|
|
}
|
|
}).content;
|
|
} catch (err) {
|
|
throw _.extend(new Error("Failed to complete OAuth handshake with Facebook. " + err.message),
|
|
{response: err.response});
|
|
}
|
|
|
|
// If 'responseContent' parses as JSON, it is an error.
|
|
// XXX which facebook error causes this behvaior?
|
|
if (isJSON(responseContent)) {
|
|
throw new Error("Failed to complete OAuth handshake with Facebook. " + responseContent);
|
|
}
|
|
|
|
// Success! Extract the facebook access token and expiration
|
|
// time from the response
|
|
var parsedResponse = querystring.parse(responseContent);
|
|
var fbAccessToken = parsedResponse.access_token;
|
|
var fbExpires = parsedResponse.expires;
|
|
|
|
if (!fbAccessToken) {
|
|
throw new Error("Failed to complete OAuth handshake with facebook " +
|
|
"-- can't find access token in HTTP response. " + responseContent);
|
|
}
|
|
return {
|
|
accessToken: fbAccessToken,
|
|
expiresIn: fbExpires
|
|
};
|
|
};
|
|
|
|
var getIdentity = function (accessToken) {
|
|
try {
|
|
return HTTP.get("https://graph.facebook.com/v2.2/me", {
|
|
params: {access_token: accessToken}}).data;
|
|
} catch (err) {
|
|
throw _.extend(new Error("Failed to fetch identity from Facebook. " + err.message),
|
|
{response: err.response});
|
|
}
|
|
};
|
|
|
|
Facebook.retrieveCredential = function(credentialToken, credentialSecret) {
|
|
return OAuth.retrieveCredential(credentialToken, credentialSecret);
|
|
};
|