Search code examples
meteormeteor-accounts

Meteor OAuth API Login


I'm creating a new Third party login using Meteor Facebook / Accounts-Facebook packages as example and I'm stuck at the following error:

Exception while invoking method 'login' Error: Service data for service storenvy must include id                                                                                                                          
at Object.Accounts.updateOrCreateUserFromExternalService (packages/accounts-base/accounts_server.js:1138)                                                                                                             
at Package (packages/accounts-oauth/oauth_server.js:45)                                                                                                                                                               
at packages/accounts-base/accounts_server.js:383                                                                                                                                                                      
at tryLoginMethod (packages/accounts-base/accounts_server.js:186)                                                                                                                                                     
at runLoginHandlers (packages/accounts-base/accounts_server.js:380)        
at tryLoginMethod (packages/accounts-base/accounts_server.js:186)                                                                                                                                                     
at runLoginHandlers (packages/accounts-base/accounts_server.js:380)                                                                                                                                                   
t Meteor.methods.login (packages/accounts-base/accounts_server.js:434)                                                                                                                                               
at maybeAuditArgumentChecks (packages/ddp/livedata_server.js:1599)                                                                                                                                                    
at packages/ddp/livedata_server.js:648                                                                                                                                                                                
_.extend.withValue (packages/meteor/dynamics_nodejs.js:56)                                                                                                                                                         
at packages/ddp/livedata_server.js:647        

My code:

    Storenvy = {};

OAuth.registerService('storenvy', 2, null, function(query) {

  var response = getTokens(query);
  var accessToken = response.accessToken;
  var identity = getIdentity(accessToken);

  var serviceData = {
    accessToken: accessToken,
    expiresAt: (+new Date) + (1000 * response.expiresIn)
  };

  // include all fields from dropbox
  // https://www.dropbox.com/developers/core/docs#account-info
  //var fields = _.pick(identity, ['first_name', 'last_name']);
  var whitelisted = ['id', 'login', 'name', 'email', 'created_at', 'bio', 'location', 'gender', 'birthday', 'facebook', 'twitter', 'avatar'];
  var fields = _.pick(identity, whitelisted);
  _.extend(serviceData, fields);

  if (response.refreshToken)
    serviceData.refreshToken = response.refreshToken;

  return {
    serviceData: serviceData,
    options: {profile: {name: identity.name}}
  };
});


// returns an object containing:
// - accessToken
// - expiresIn: lifetime of token in seconds
var getTokens = function (query) {
  var config = ServiceConfiguration.configurations.findOne({service: 'storenvy'});
  if (!config)
    throw new ServiceConfiguration.ConfigError();

  var response;
  try {
    // Request an access token
    response = HTTP.post(
      "https://api.storenvy.com/oauth/token", {params: {
        client_id: config.appId,
        client_secret: OAuth.openSecret(config.secret),
        code: query.code,
        grant_type: 'authorization_code',
        redirect_uri: OAuth._redirectUri('storenvy', config)
      }});
  } catch (err) {
    throw _.extend(new Error("Failed to complete OAuth handshake with storenvy1. " + err.message),
                   {response: err.response});
  }

  if (response.data.error) { // if the http response was a json object with an error attribute
    throw new Error("Failed to complete OAuth handshake with storenvy2. " + response.data.error);
  } else {
    return {
      accessToken: response.data.access_token,
      refreshToken: response.data.refresh_token,
      expiresIn: response.data.expires_in
    };
  }
};

var getIdentity = function (accessToken) {
  try {
    return Meteor.http.get("https://api.storenvy.com/v1/me", 
        {params: {access_token: accessToken}}).data;
  } catch (err) {
    throw new Error("Failed to fetch identity from storenvy. " + err.message);
  }
};

Storenvy.retrieveCredential = function(credentialToken, credentialSecret) {
  return OAuth.retrieveCredential(credentialToken, credentialSecret);
};

I really can't figure out what or how var getIdentity and code below work. There is lack of document ion for this as I can't find anything so your help is very much appreciated! serviceData: serviceData, options: {profile: {name: identity.name}}


Solution

  • OK so I figured it out: serviceData add ID to it and it works! var serviceData = { id: identity.data.id, email: identity.data.email, username: identity.data.login, accessToken: accessToken, expiresAt: (+new Date) + (1000 * response.expiresIn) };