OAuth failed from my server


#1

Hello, I’m writing some nodejs code on my server which needs to call the Particle REST Api.
I created an OAuth client (two legged authentication) and I pass the client_id and the client_secret to loginAsClientOwner function of the Particle js SDK.
Unluckily I cannot authenticate, and I get the following error:

“HTTP error 400 from https://api.particle.io/oauth/token - The grant type is unauthorised for this client_id”

Any of you can guess what’s going wrong ?

Here’s the code that generates the error, thank you in advance for your help.

Antonio

const configSettings = require('config');
const Particle = require('particle-api-js');
const logger = require('./logger');

const particle = new Particle();
var particleToken;

const clientId = configSettings.get('particle.client_id');
const clientSecret = configSettings.get('particle.client_secret');

particle.loginAsClientOwner({ client_id: clientId, client_secret: clientSecret })
.then((data) => { particleToken = data.body.access_token; })
.catch((error) => { logger.logError(error); });

#2

Reading again all the docs I found this sentence (in the tutorial):

"2. Add OAuth Credentials to SDK
For both the mobile & JavaScript SDKs, you will need to add your client credentials to a configuration file. The client application will need the client credentials that you just generated "

So, I guess I don’t need to send the cliend ID and secret as params when calling the login function, but I need to save them somewhere in a configuration file of the SDK.

But where it is ?


#3

Hmmmmm, I just found out in the source code of the SDK the Default.js file where I can read:

export default {
	baseUrl: 'https://api.particle.io',
	clientSecret: 'particle-api',
	clientId: 'particle-api',
	tokenDuration: 7776000 // 90 days
};

So, now the question I think is: How can I change these defaults ?
Hope the answer is not to change the source code of the SDK.


#4

Ok, I solved this.
For others of you who will face the same problem, here’s how to do it (quite easy indeed):

The defaults are saved in internal clientId and clientSecret variables in Particle constructor (Particle.js):

	constructor(options = {}) {
		// todo - this seems a bit dangerous - would be better to put all options/context in a contained object
		Object.assign(this, Defaults, options);
		this.context = {};
		this.agent = new Agent(this.baseUrl);
	}

So, that’s just a matter of changing them:

// I get the credentials saved in a json configuration file
const clientId = configSettings.get('particle.client_id');
const clientSecret = configSettings.get('particle.client_secret');

// I save the credential in the Particle object to overwrite the default values
particle.clientId = clientId;
particle.clientSecret = clientSecret;

// And not I can connect 
particle.loginAsClientOwner({})
.then((data) => { 
	token = data.body.access_token; 
	connected = true;
	logger.logStartupMessage("Connected to Particle Cloud with ClientID/Secret") 
})
.catch((error) => { 
	connected = false;
	logger.logError(error); 
});

#5

I tried to follow you code example as good as I could. But it does not seem to work for me.

const functions = require('firebase-functions')
const Particle = require('particle-api-js')
const configSettings = require('./configSettings.json')

// Create and Deploy Your First Cloud Functions
// https://firebase.google.com/docs/functions/write-firebase-functions

exports.helloWorld = functions.https.onRequest((request, response) => {
  // Start a particle instance
  const particle = new Particle()

  // Setup the client access
  particle.clientId = configSettings.clientId
  particle.clientSecret = configSettings.clientSecret

  // Start the client to get an access token
  particle.loginAsClientOwner({}).then(
    function(data) {
      // Grab the token
      const token = data.body.access_token

      // Call the print function that should be exposed by `Particle.function("print", methodThatPrints)`
      particle.callFunction({
        deviceId: configSettings.deviceId,
        name: 'print',
        argument: '"Hello **fire**base"',
        auth: token,
      })
    },
    function(err) {
      console.log('API call completed on promise fail: ', err)
    }
  )
  response.send('Printed..')
})

But it throws this error at me

Error: HTTP error 400 from https://api.particle.io/v1/devices/[DEVICEID]/print - Permission denied at /srv/node_modules/particle-api-js/lib/Agent.js:204:19 at Request.callback (/srv/node_modules/superagent/lib/node/index.js:728:3) at parser (/srv/node_modules/superagent/lib/node/index.js:916:18) at IncomingMessage.res.on (/srv/node_modules/superagent/lib/node/parsers/json.js:19:7) at emitNone (events.js:111:20) at IncomingMessage.emit (events.js:208:7) at endReadableNT (_stream_readable.js:1064:12) at _combinedTickCallback (internal/process/next_tick.js:139:11) at process._tickDomainCallback (internal/process/next_tick.js:219:9)

Bonus info: I got two-step authentication enabled… That’s why I try to use the Particle.loginAsClientOwner({}).


#6

Maybe due to the typo in the assignment of the client secret.


#7

@woodwhcker Thank you for pointing out the typo. The typo wasn’t present in the code I deployed to the servers. I have fixed it now in my post.

I still can’t get it to work.


#8

I tried to disable the the two-step authentication and do a Particle.login and it worked as expected. So my question is how do I keep on the 2-step?