Repository: auth0/auth0.js
Pull request #265 (2016-12-07 20:51:20)

Login with password realm grant via /oauth/token


Patch:
diff --git a/src/authentication/index.js b/src/authentication/index.js
index c1003ac..ceea503 100644
--- a/src/authentication/index.js
+++ b/src/authentication/index.js
@@ -80,6 +80,10 @@ Authentication.prototype.buildAuthorizeUrl = function (options) {
     params.auth0Client = this.request.getTelemetryData();
   }
 
+  if (params.connection_scope && assert.isArray(params.connection_scope)) {
+    params.connection_scope = params.connection_scope.join(',');
+  }
+
   params = objectHelper.toSnakeCase(params, ['auth0Client']);
   params = parametersWhitelist.oauthAuthorizeParams(params);
 
@@ -113,7 +117,7 @@ Authentication.prototype.buildLogoutUrl = function (options) {
   return urljoin(this.baseOptions.rootUrl, 'v2', 'logout', '?' + qString);
 };
 
-Authentication.prototype.login = function (options, cb) {
+Authentication.prototype.loginWithDefaultDirectory = function (options, cb) {
   assert.check(options, { type: 'object', message: 'options parameter is not valid' }, {
     username: { type: 'string', message: 'username option is required' },
     password: { type: 'string', message: 'password option is required' }
@@ -124,6 +128,18 @@ Authentication.prototype.login = function (options, cb) {
   return this.oauthToken(options, cb);
 };
 
+Authentication.prototype.login = function (options, cb) {
+  assert.check(options, { type: 'object', message: 'options parameter is not valid' }, {
+    username: { type: 'string', message: 'username option is required' },
+    password: { type: 'string', message: 'password option is required' },
+    realm: { type: 'string', message: 'realm option is required' }
+  });
+
+  options.grantType = 'http://auth0.com/oauth/grant-type/password-realm';
+
+  return this.oauthToken(options, cb);
+};
+
 Authentication.prototype.oauthToken = function (options, cb) {
   var url;
   var body;
@@ -147,6 +163,7 @@ Authentication.prototype.oauthToken = function (options, cb) {
   });
 
   body = objectHelper.toSnakeCase(body, ['auth0Client']);
+  body = parametersWhitelist.oauthTokenParams(body);
 
   body.grant_type = body.grant_type;
 
diff --git a/src/helper/parameters-whitelist.js b/src/helper/parameters-whitelist.js
index 4c64b50..02d7d8c 100644
--- a/src/helper/parameters-whitelist.js
+++ b/src/helper/parameters-whitelist.js
@@ -1,8 +1,28 @@
 var objectHelper = require('../helper/object');
 
+var token_params = [
+// auth0
+  'realm',
+// oauth2
+  'client_id',
+  'client_secret',
+  'redirect_uri',
+  'scope',
+  'code',
+  'grant_type',
+  'username',
+  'password',
+  'refresh_token',
+  'assertion',
+  'client_assertion',
+  'client_assertion_type',
+  'code_verifier'
+];
+
 var authorize_params = [
 // auth0
   'connection',
+  'connection_scope',
   'auth0Client',
   'owp',
 // oauth2
@@ -34,6 +54,11 @@ function oauthAuthorizeParams(params) {
   return objectHelper.pick(params, authorize_params);
 }
 
+function oauthTokenParams(params) {
+  return objectHelper.pick(params, token_params);
+}
+
 module.exports = {
+  oauthTokenParams: oauthTokenParams,
   oauthAuthorizeParams: oauthAuthorizeParams
 };


Test patch:
diff --git a/test/authentication/authentication.test.js b/test/authentication/authentication.test.js
index f23d267..bd94398 100644
--- a/test/authentication/authentication.test.js
+++ b/test/authentication/authentication.test.js
@@ -65,6 +65,30 @@ describe('auth0.authentication', function () {
       expect(url).to.be('https://me.auth0.com/authorize?client_id=...&response_type=code&redirect_uri=http%3A%2F%2Fpage.com%2Fcallback&state=1234');
     })
 
+    it('should return a url with connection_scope', function() {
+      var url = this.auth0.buildAuthorizeUrl({
+        responseType: 'token',
+        redirectUri: 'http://anotherpage.com/callback2',
+        prompt: 'none',
+        state: '1234',
+        connection_scope: 'scope1,scope2'
+      });
+
+      expect(url).to.be('https://me.auth0.com/authorize?connection_scope=scope1%2Cscope2&client_id=...&response_type=token&redirect_uri=http%3A%2F%2Fanotherpage.com%2Fcallback2&state=1234&prompt=none');
+    })
+
+    it('should return a url with connection_scope as a string', function() {
+      var url = this.auth0.buildAuthorizeUrl({
+        responseType: 'token',
+        redirectUri: 'http://anotherpage.com/callback2',
+        prompt: 'none',
+        state: '1234',
+        connection_scope: ['scope1', 'scope2']
+      });
+
+      expect(url).to.be('https://me.auth0.com/authorize?connection_scope=scope1%2Cscope2&client_id=...&response_type=token&redirect_uri=http%3A%2F%2Fanotherpage.com%2Fcallback2&state=1234&prompt=none');
+    })
+
     it('should return a url using overriding the default settings', function() {
       var url = this.auth0.buildAuthorizeUrl({
         responseType: 'token',
@@ -295,13 +319,33 @@ describe('auth0.authentication', function () {
         cb();
       });
 
-      this.auth0.login({
+      this.auth0.loginWithDefaultDirectory({
         username: 'someUsername',
         password: '123456'
       }, function(err, data) {
         done();
       })
     });
+
+    it('should call oauthToken with all the options', function(done) {
+      stub(this.auth0, 'oauthToken', function(options, cb) {
+        expect(options).to.eql({
+          username: 'someUsername',
+          password: '123456',
+          grantType: 'http://auth0.com/oauth/grant-type/password-realm',
+          realm: 'pepe.com'
+        })
+        cb();
+      });
+
+      this.auth0.login({
+        username: 'someUsername',
+        password: '123456',
+        realm: 'pepe.com'
+      }, function(err, data) {
+        done();
+      })
+    });
   });
 
   context('oauthToken', function () {