Custom OAuth getting 'loginWithService is not a function'


#1

I copied ‘google’ and ‘accounts-google’ to my local packages directory and made a few changes to make it compatible with cisco spark as an oauth provider.

It was working great, so I thought I would share my success and publish ‘ciscospark’ and ‘accounts-ciscospark’

So I renamed all references, filenames, packages, etc and reset my meteor project.

Unlike ‘loginWithGoogle’ that is clearly published as an available function here:
https://docs.meteor.com/api/accounts.html#Meteor-loginWith<ExternalService>

I’m using a custom service, which I would assume would work the same, ie loginWithCiscoSpark.

Heres the relevant code.

ciscospark.js
Accounts.oauth.registerService(‘ciscospark’);
Meteor.loginWithCiscoSpark = function(options, callback) { … }

ciscospark_server.js
CiscoSpark = {};
OAuth.registerService(‘ciscospark’, 2, null, function(query)

ciscospark_client.js
CiscoSpark = {};
var config = ServiceConfiguration.configurations.findOne({service: ‘ciscospark’});
OAuth.launchLogin({
loginService: “ciscospark”,
loginStyle: loginStyle,
loginUrl: loginUrl,
credentialRequestCompleteCallback: credentialRequestCompleteCallback,
credentialToken: credentialToken,
popupOptions: { height: 600 }
});

accounts.js
ServiceConfiguration.configurations.update(
{ service: “ciscospark” },
{ $set: {
loginStyle: ‘popup’,
clientId: ‘redacted’,
secret: ‘redacted’
}
},
{ upsert: true }
);


#2

I wrote a guide a while ago for creating a custom Oauth service. If it will add any clarity, please check it out.


#3

@robfallows I used your guide to create an implementation for Auth0, worked quite well, so thank you! :smiley:

@levensailor can you share your callback function in OAuth.registerService?


#4

so the problem was that it needed to call loginWithCiscospark not loginWithCiscoSpark
the meteor code capitalizes the servicename ciscospark to Ciscospark.

Your guide was awesome @robfallows it was another where I read upperCamelCase was required.

this is described here:
meteor-release-METEOR-1.3.5.1\packages\accounts-ui-unstyled\login_buttons_single.js

Template._loginButtonsLoggedOutSingleLoginButton.events({
‘click .login-button’: function () {
var serviceName = this.name;
loginButtonsSession.resetMessages();

// XXX Service providers should be able to specify their
// `Meteor.loginWithX` method name.
var loginWithService = Meteor["loginWith" +
                              (serviceName === 'meteor-developer' ?
                               'MeteorDeveloperAccount' :
                               capitalize(serviceName))];

var options = {}; // use default scope unless specified
if (Accounts.ui._options.requestPermissions[serviceName])
  options.requestPermissions = Accounts.ui._options.requestPermissions[serviceName];
if (Accounts.ui._options.requestOfflineToken[serviceName])
  options.requestOfflineToken = Accounts.ui._options.requestOfflineToken[serviceName];
if (Accounts.ui._options.forceApprovalPrompt[serviceName])
  options.forceApprovalPrompt = Accounts.ui._options.forceApprovalPrompt[serviceName];

loginWithService(options, function (err) {
  loginResultCallback(serviceName, err);
});

}
});


#5

Where to go from here…

So I know the oAuth flow works because I got an auth token and I can use it to pull my own display name and console it out. I’m doing that in the ciscospark_server.js

var identity = getIdentity(accessToken);
console.log(identity.displayName);

Two things i’m stuck on:

  1. the window doesn’t close using popup loginStyle.
  2. Is there a best practice to linking the oAuth service user fields to the local users database? I would imagine an upsert just mapping what i need? I’m strictly using this one service so its really a single sign on.

#6
  1. I was using localhost instead of my root_url in the browser so it didn’t know how to close. fixed

  2. where else would the oauth values get inserted into the database if not getIdentity?