Meetup = {};

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

  var accessToken = getAccessToken(query);
  var identity = getIdentity(accessToken);

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

var getAccessToken = function (query) {
  var config = ServiceConfiguration.configurations.findOne({service: 'meetup'});
  if (!config)
    throw new ServiceConfiguration.ConfigError();

  var response;
  try {
    response = HTTP.post(
      "https://secure.meetup.com/oauth2/access", {headers: {Accept: 'application/json'}, params: {
        code: query.code,
        client_id: config.clientId,
        client_secret: OAuth.openSecret(config.secret),
        grant_type: 'authorization_code',
        redirect_uri: OAuth._redirectUri('meetup', config),
        state: query.state
      }});
  } catch (err) {
    throw _.extend(new Error("Failed to complete OAuth handshake with Meetup. " + 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 Meetup. " + response.data.error);
  } else {
    return response.data.access_token;
  }
};

var getIdentity = function (accessToken) {
  try {
    var response = HTTP.get(
      "https://api.meetup.com/2/members",
      {params: {member_id: 'self', access_token: accessToken}});
    return response.data.results && response.data.results[0];
  } catch (err) {
    throw _.extend(new Error("Failed to fetch identity from Meetup. " + err.message),
                   {response: err.response});
  }
};


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

@@ -73,27 +73,24 @@
 %0A%0A  var 
-accessToken
+response
  = getAc
@@ -107,16 +107,121 @@
 query);%0A
+  var accessToken = response.access_token;%0A  var expiresAt = (+new Date) + (1000 * response.expires_in);%0A
   var id
@@ -309,16 +309,16 @@
 ity.id,%0A
-
       ac
@@ -339,16 +339,44 @@
 essToken
+,%0A      expiresAt: expiresAt
 %0A    %7D,%0A
@@ -1415,29 +1415,16 @@
 nse.data
-.access_token
 ;%0A  %7D%0A%7D;

Store expiresAt for all OAuth providers (#8547).