Skip to content

Commit

Permalink
Merge 3fd2466 into 69e26e5
Browse files Browse the repository at this point in the history
  • Loading branch information
glena committed Oct 7, 2016
2 parents 69e26e5 + 3fd2466 commit d9089b2
Show file tree
Hide file tree
Showing 4 changed files with 243 additions and 9 deletions.
40 changes: 37 additions & 3 deletions src/auth/OAuthAuthenticator.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ var RestClient = require('rest-facade').Client;
* @constructor
* @memberOf module:auth
*
* @param {Object} options Authenticator options.
* @param {String} options.baseUrl The auth0 account URL.
* @param {String} [options.clientId] Default client ID.
* @param {Object} options Authenticator options.
* @param {String} options.baseUrl The auth0 account URL.
* @param {String} [options.clientId] Default client ID.
* @param {String} [options.clientSecret] Default client Secret.
*/
var OAuthAuthenticator = function (options) {
if (!options) {
Expand All @@ -28,6 +29,7 @@ var OAuthAuthenticator = function (options) {

this.oauth = new RestClient(oauthUrl);
this.clientId = options.clientId;
this.clientSecret = options.clientSecret;
};


Expand Down Expand Up @@ -136,5 +138,37 @@ OAuthAuthenticator.prototype.socialSignIn = function (data, cb) {
return this.oauth.create(params, data);
};

OAuthAuthenticator.prototype.clientCredentialsGrant = function(options, cb) {

var params = {
type: 'token'
};

var defaultFields = {
grant_type: "client_credentials",
client_id: this.clientId,
client_secret: this.clientSecret
};

var data = extend(defaultFields, options);

if (!options || typeof options !== 'object') {
throw new ArgumentError('Missing options object');
}

if (!data.client_id || data.client_id.trim().length === 0) {
throw new ArgumentError('client_id field is required');
}

if (!data.client_secret || data.client_secret.trim().length === 0) {
throw new ArgumentError('client_secret field is required');
}

if (cb && cb instanceof Function) {
return this.oauth.create(params, data, cb);
}

return this.oauth.create(params, data);
};

module.exports = OAuthAuthenticator;
36 changes: 32 additions & 4 deletions src/auth/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,11 @@ var BASE_URL_FORMAT = 'https://%s';
* clientId: '{OPTIONAL_CLIENT_ID}'
* });
*
* @param {Object} options Options for the Authentication Client
* SDK.
* @param {String} options.domain AuthenticationClient server domain.
* @param {String} [options.clientId] Default client ID.
* @param {Object} options Options for the Authentication Client
* SDK.
* @param {String} options.domain AuthenticationClient server domain.
* @param {String} [options.clientId] Default client ID.
* @param {String} [options.clientSecret] Default client Secret.
*/
var AuthenticationClient = function (options) {
if (!options || typeof options !== 'object') {
Expand All @@ -58,6 +59,8 @@ var AuthenticationClient = function (options) {

var managerOptions = {
clientId: options.clientId,
domain: options.domain,
clientSecret: options.clientSecret,
headers: {
'User-agent': 'node.js/' + process.version.replace('v', ''),
'Content-Type': 'application/json'
Expand Down Expand Up @@ -476,5 +479,30 @@ AuthenticationClient.prototype.requestChangePasswordEmail = function (data, cb)
*/
utils.wrapPropertyMethod(AuthenticationClient, 'getProfile', 'users.getInfo');

/**
* Gets an access token using the client credentials grant flow.
*
* @method clientCredentialsGrant
* @memberOf module:auth.AuthenticationClient.prototype
*
* @example <caption>
* Gets an access token using the client credentials grant flow. Find more information in the
* <a href="https://auth0.com/docs/api-auth/config/asking-for-access-tokens">API Docs</a>.
* </caption>
*
* auth0.clientCredentialsGrant(data, function (err, response) {
* if (err) {
* // Handle error.
* }
*
* console.log(response);
* });
*
* @param {String} scope
*
* @return {Promise|undefined}
*/
utils.wrapPropertyMethod(AuthenticationClient, 'clientCredentialsGrant', 'oauth.clientCredentialsGrant');


module.exports = AuthenticationClient;
1 change: 0 additions & 1 deletion src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,5 +72,4 @@ utils.getRequestPromise = function (settings) {
});

});

}
175 changes: 174 additions & 1 deletion test/auth/oauth.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ var SRC_DIR = '../../src';
var DOMAIN = 'tenant.auth0.com';
var API_URL = 'https://' + DOMAIN;
var CLIENT_ID = 'TEST_CLIENT_ID';
var CLIENT_SECRET = 'TEST_CLIENT_SECRET';

var ArgumentError = require(SRC_DIR + '/exceptions').ArgumentError;
var Authenticator = require(SRC_DIR + '/auth/OAuthAuthenticator');

var validOptions = {
baseUrl: API_URL,
clientId: CLIENT_ID
clientId: CLIENT_ID,
clientSecret: CLIENT_SECRET,
};


Expand Down Expand Up @@ -465,4 +467,175 @@ describe('OAuthAuthenticator', function () {
});
});

describe('#clientCredentials', function () {
var path = '/oauth/token';
var options = {
audience: 'audience',
scope: 'scope'
};

beforeEach(function () {
this.authenticator = new Authenticator(validOptions);
this.request = nock(API_URL)
.post(path)
.reply(200);
});


it('should require an object as first argument', function () {
expect(this.authenticator.clientCredentialsGrant)
.to.throw(ArgumentError, 'Missing options object');
});

it('should accept a callback', function (done) {
this
.authenticator
.clientCredentialsGrant(options, done.bind(null, null));
});


it('should return a promise when no callback is provided', function (done) {
this
.authenticator
.clientCredentialsGrant(options)
.then(done.bind(null, null))
.catch(done.bind(null, null));
});


it('should perform a POST request to ' + path, function (done) {
var request = this.request;

this
.authenticator
.clientCredentialsGrant(options)
.then(function () {
expect(request.isDone())
.to.be.true;

done();
})
.catch(done);
});


it('should include the options in the request', function (done) {
nock.cleanAll();

var request = nock(API_URL)
.post(path, function (body) {
for (var property in options) {
if (options[property] !== body[property]) {
return false;
}
}

return true;
})
.reply(200);

this
.authenticator
.clientCredentialsGrant(options)
.then(function () {
expect(request.isDone())
.to.be.true;

done();
})
.catch(done);
});


it('should include the Auth0 client ID and secret in the request', function (done) {
nock.cleanAll();

var request = nock(API_URL)
.post(path, function (body) {
return body.client_id === CLIENT_ID;
return body.client_secret === CLIENT_SECRET;
})
.reply(200);

this
.authenticator
.clientCredentialsGrant(options)
.then(function () {
expect(request.isDone())
.to.be.true;

done();
})
.catch(done);
});


it('should allow the user to specify the audience and scope', function (done) {
nock.cleanAll();

var request = nock(API_URL)
.post(path, function (body) {
return body.audience === 'audience' && body.scope === 'scope';
})
.reply(200);

this
.authenticator
.clientCredentialsGrant(options)
.then(function () {
expect(request.isDone())
.to.be.true;

done();
})
.catch(done);
});


it('should use client_credentials as default grant type', function (done) {
nock.cleanAll();

var request = nock(API_URL)
.post(path, function (body) {
return body.grant_type === 'client_credentials';
})
.reply(200);

this
.authenticator
.clientCredentialsGrant(options)
.then(function () {
expect(request.isDone())
.to.be.true;

done();
})
.catch(done);
});


it('should allow the user to specify the grant type', function (done) {
nock.cleanAll();

var data = extend({ grant_type: 'TEST_GRANT' }, options);
var request = nock(API_URL)
.post(path, function (body) {
return body.grant_type === 'TEST_GRANT';
})
.reply(200);

this
.authenticator
.clientCredentialsGrant(data)
.then(function () {
expect(request.isDone())
.to.be.true;

done();
})
.catch(done);
});

});

});

0 comments on commit d9089b2

Please sign in to comment.