diff --git a/example/index.html b/example/index.html
index fff7faa5..564a7f75 100644
--- a/example/index.html
+++ b/example/index.html
@@ -12,6 +12,7 @@
}
pre {
margin: 0 0 10px 0;
+ min-height: 300px;
}
code {
min-height: 300px;
@@ -39,15 +40,40 @@
diff --git a/src/authentication/db-connection.js b/src/authentication/db-connection.js
index dc74e3f7..9131cf4e 100644
--- a/src/authentication/db-connection.js
+++ b/src/authentication/db-connection.js
@@ -29,7 +29,7 @@ DBConnection.prototype.signup = function (options, cb) {
body = objectHelper.toSnakeCase(body, ['auth0Client']);
- this.request
+ return this.request
.post(url)
.send(body)
.end(responseHandler(cb));
@@ -52,7 +52,7 @@ DBConnection.prototype.changePassword = function (options, cb) {
body = objectHelper.toSnakeCase(body, ['auth0Client']);
- this.request
+ return this.request
.post(url)
.send(body)
.end(responseHandler(cb));
diff --git a/src/authentication/index.js b/src/authentication/index.js
index f1a4be61..a924d249 100644
--- a/src/authentication/index.js
+++ b/src/authentication/index.js
@@ -91,7 +91,49 @@ Authentication.prototype.buildLogoutUrl = function (options) {
return urljoin(this.baseOptions.rootUrl, 'v2', 'logout', '?' + qString);
};
-Authentication.prototype.ro = function (options, cb) {
+Authentication.prototype.login = function (options, cb) {
+ assert.check(options, { type: 'object', message: 'options parameter is not valid' }, {
+ clientID: { optional: true, type: 'string', message: 'clientID option is required' },
+ username: { optional: true, type: 'string', message: 'username option is required' },
+ password: { optional: true, type: 'string', message: 'password option is required' },
+ scope: { optional: true, type: 'string', message: 'scope option is required' },
+ audience: { optional: true, type: 'string', message: 'audience option is required' }
+ });
+ assert.check(cb, { type: 'function', message: 'cb parameter is not valid' });
+
+ options.grantType = 'password';
+
+ return this.oauthToken(options, cb);
+};
+
+Authentication.prototype.oauthToken = function (options, cb) {
+ var url;
+ var body;
+
+ assert.check(options, { type: 'object', message: 'options parameter is not valid' }, {
+ grantType: { optional: true, type: 'string', message: 'grantType option is required' }
+ });
+ assert.check(cb, { type: 'function', message: 'cb parameter is not valid' });
+
+ url = urljoin(this.baseOptions.rootUrl, 'oauth', 'token');
+
+ body = objectHelper.merge(this.baseOptions, [
+ 'clientID',
+ 'scope',
+ 'audience'
+ ]).with(options);
+
+ body = objectHelper.toSnakeCase(body, ['auth0Client']);
+
+ body.grant_type = body.grant_type || 'password';
+
+ return this.request
+ .post(url)
+ .send(body)
+ .end(responseHandler(cb));
+};
+
+Authentication.prototype.loginWithResourceOwner = function (options, cb) {
var url;
var body;
@@ -106,14 +148,17 @@ Authentication.prototype.ro = function (options, cb) {
url = urljoin(this.baseOptions.rootUrl, 'oauth', 'ro');
- body = objectHelper.merge(this.baseOptions, ['clientID'])
- .with(options);
+ body = objectHelper.merge(this.baseOptions, [
+ 'clientID',
+ 'scope',
+ 'audience'
+ ]).with(options);
body = objectHelper.toSnakeCase(body, ['auth0Client']);
body.grant_type = body.grant_type || 'password';
- this.request
+ return this.request
.post(url)
.send(body)
.end(responseHandler(cb));
@@ -127,7 +172,7 @@ Authentication.prototype.userInfo = function (accessToken, cb) {
url = urljoin(this.baseOptions.rootUrl, 'userinfo');
- this.request
+ return this.request
.get(url)
.set('Authorization', 'Bearer ' + accessToken)
.end(responseHandler(cb));
@@ -149,7 +194,7 @@ Authentication.prototype.delegation = function (options, cb) {
body = objectHelper.toSnakeCase(body, ['auth0Client']);
- this.request
+ return this.request
.post(url)
.send(body)
.end(responseHandler(cb));
diff --git a/src/authentication/passwordless-authentication.js b/src/authentication/passwordless-authentication.js
index 2bff61c1..3bce4219 100644
--- a/src/authentication/passwordless-authentication.js
+++ b/src/authentication/passwordless-authentication.js
@@ -83,7 +83,7 @@ PasswordlessAuthentication.prototype.start = function (options, cb) {
body = objectHelper.toSnakeCase(body, ['auth0Client']);
- this.request
+ return this.request
.post(url)
.send(body)
.end(responseHandler(cb));
@@ -114,7 +114,7 @@ PasswordlessAuthentication.prototype.verify = function (options, cb) {
url = urljoin(this.baseOptions.rootUrl, 'passwordless', 'verify');
- this.request
+ return this.request
.post(url)
.send(cleanOption)
.end(responseHandler(cb));
diff --git a/src/helper/request-builder.js b/src/helper/request-builder.js
index 67560b84..61662354 100644
--- a/src/helper/request-builder.js
+++ b/src/helper/request-builder.js
@@ -3,6 +3,59 @@ var request = require('superagent');
var base64Url = require('./base64_url');
var version = require('../version');
+// ------------------------------------------------ RequestWrapper
+
+function RequestWrapper(req) {
+ this.request = req;
+ this.method = req.method;
+ this.url = req.url;
+ this.body = req._data;
+ this.headers = req._header;
+}
+
+RequestWrapper.prototype.abort = function () {
+ this.request.abort();
+};
+
+RequestWrapper.prototype.getMethod = function () {
+ return this.method;
+};
+
+RequestWrapper.prototype.getBody = function () {
+ return this.body;
+};
+
+RequestWrapper.prototype.getUrl = function () {
+ return this.url;
+};
+
+RequestWrapper.prototype.getHeaders = function () {
+ return this.headers;
+};
+
+// ------------------------------------------------ RequestObj
+
+function RequestObj(req) {
+ this.request = req;
+}
+
+RequestObj.prototype.set = function (key, value) {
+ this.request = this.request.set(key, value);
+ return this;
+};
+
+RequestObj.prototype.send = function (body) {
+ this.request = this.request.send(body);
+ return this;
+};
+
+RequestObj.prototype.end = function (cb) {
+ this.request = this.request.end(cb);
+ return new RequestWrapper(this.request);
+};
+
+// ------------------------------------------------ RequestBuilder
+
function RequestBuilder(options) {
this._sendTelemetry = options._sendTelemetry === false ? options._sendTelemetry : true;
this._telemetryInfo = options._telemetryInfo || null;
@@ -28,15 +81,15 @@ RequestBuilder.prototype.getTelemetryData = function () {
};
RequestBuilder.prototype.get = function (url) {
- return this.setCommonConfiguration(request.get(url));
+ return new RequestObj(this.setCommonConfiguration(request.get(url)));
};
RequestBuilder.prototype.post = function (url) {
- return this.setCommonConfiguration(request.post(url));
+ return new RequestObj(this.setCommonConfiguration(request.post(url)));
};
RequestBuilder.prototype.patch = function (url) {
- return this.setCommonConfiguration(request.patch(url));
+ return new RequestObj(this.setCommonConfiguration(request.patch(url)));
};
module.exports = RequestBuilder;
diff --git a/src/helper/response-handler.js b/src/helper/response-handler.js
index 02587b19..5352c696 100644
--- a/src/helper/response-handler.js
+++ b/src/helper/response-handler.js
@@ -1,7 +1,28 @@
function wrapCallback(cb) {
return function (err, data) {
+
if (err) {
- return cb(err);
+ var data = {
+ original: err
+ };
+
+ if (err.response && err.response.statusCode) {
+ data.status_code = err.response.statusCode;
+ }
+
+ if (err.response && err.response.statusText) {
+ data.status_text = err.response.statusText;
+ }
+
+ if (err.response && err.response.body) {
+ err = err.response.body;
+ }
+
+ data.code = err.error || err.code || err.error_code || null;
+ data.description = err.error_description || err.description || err.error || null;
+ data.name = err.name || null;
+
+ return cb(data);
}
return cb(null, data.body || data.text);
diff --git a/src/management/index.js b/src/management/index.js
index dce1de24..445538cb 100644
--- a/src/management/index.js
+++ b/src/management/index.js
@@ -30,7 +30,7 @@ Management.prototype.getUser = function (userId, cb) {
url = urljoin(this.baseOptions.rootUrl, 'users', userId);
- this.request
+ return this.request
.get(url)
.end(responseHandler(cb));
};
@@ -44,24 +44,24 @@ Management.prototype.patchUserMetadata = function (userId, userMetadata, cb) {
url = urljoin(this.baseOptions.rootUrl, 'users', userId);
- this.request
+ return this.request
.patch(url)
.send({ user_metadata: userMetadata })
.end(responseHandler(cb));
};
-Management.prototype.linkUsers = function (userId, secondaryUserToken, cb) {
+Management.prototype.linkUser = function (userId, secondaryUserToken, cb) {
var url;
/* eslint-disable */
assert.check(userId, { type: 'string', message: 'userId parameter is not valid' });
- assert.check(secondaryUserToken, { type: 'string',
+ assert.check(secondaryUserToken, { type: 'string',
message: 'secondaryUserToken parameter is not valid' });
assert.check(cb, { type: 'function', message: 'cb parameter is not valid' });
/* eslint-enable */
url = urljoin(this.baseOptions.rootUrl, 'users', userId, 'identities');
- this.request
+ return this.request
.post(url)
.send({ link_with: secondaryUserToken })
.end(responseHandler(cb));
diff --git a/src/web-auth/index.js b/src/web-auth/index.js
index e6e21fb5..c58579e8 100644
--- a/src/web-auth/index.js
+++ b/src/web-auth/index.js
@@ -7,6 +7,7 @@ var objectHelper = require('../helper/object');
var Authentication = require('../authentication');
var Redirect = require('./redirect');
var SilentAuthenticationHandler = require('./silent-authentication-handler');
+var windowHelper = require('../helper/window');
function WebAuth(options) {
/* eslint-disable */
@@ -30,8 +31,8 @@ function WebAuth(options) {
this.baseOptions.tenant = this.baseOptions.domain.split('.')[0];
- this.authentication = new Authentication(this.baseOptions);
- this.redirect = new Redirect(this.authentication, this.baseOptions);
+ this.client = new Authentication(this.baseOptions);
+ this.redirect = new Redirect(this.client, this.baseOptions);
}
WebAuth.prototype.parseHash = function (hash) {
@@ -92,7 +93,7 @@ WebAuth.prototype.parseHash = function (hash) {
WebAuth.prototype.renewAuth = function (options, cb) {
var handler;
- var usePostMessage = options.usePostMessage || false;
+ var usePostMessage = !!options.usePostMessage;
var params = objectHelper.merge(this.baseOptions, [
'clientID',
@@ -114,20 +115,44 @@ WebAuth.prototype.renewAuth = function (options, cb) {
params = objectHelper.toSnakeCase(params, ['auth0Client']);
- handler = new SilentAuthenticationHandler(this, this.authentication.buildAuthorizeUrl(params));
+ handler = new SilentAuthenticationHandler(this, this.client.buildAuthorizeUrl(params));
handler.login(usePostMessage, cb);
};
WebAuth.prototype.changePassword = function (options, cb) {
- this.authentication.dbConnection.changePassword(options, cb);
+ return this.client.dbConnection.changePassword(options, cb);
};
WebAuth.prototype.passwordlessStart = function (options, cb) {
- this.authentication.passwordless.start(options, cb);
+ return this.client.passwordless.start(options, cb);
+};
+
+WebAuth.prototype.signup = function (options, cb) {
+ return this.client.dbConnection.signup(options, cb);
+};
+
+WebAuth.prototype.login = function (options) {
+ windowHelper.redirect(this.client.buildAuthorizeUrl(options));
+};
+
+WebAuth.prototype.logout = function (options) {
+ windowHelper.redirect(this.client.buildLogoutUrl(options));
+};
+
+WebAuth.prototype.passwordlessVerify = function (options, cb) {
+ var _this = this;
+ return this.client.passwordless.verify(options, function (err) {
+ if (err) {
+ return cb(err);
+ }
+ windowHelper.redirect(_this.client.passwordless.buildVerifyUrl(options));
+ });
};
+
// popup.login
+// popup.authorize
// popup.passwordlessVerify
-// popup.signup
+// popup.signupAndLogin
module.exports = WebAuth;
diff --git a/src/web-auth/redirect.js b/src/web-auth/redirect.js
index 3785f97b..bbdae436 100644
--- a/src/web-auth/redirect.js
+++ b/src/web-auth/redirect.js
@@ -1,22 +1,14 @@
var windowHelper = require('../helper/window');
var UsernamePassword = require('./username-password');
-function Redirect(authentication, options) {
+function Redirect(client, options) {
this.baseOptions = options;
- this.authentication = authentication;
+ this.client = client;
}
-Redirect.prototype.authorize = function (options) {
- windowHelper.redirect(this.authentication.buildAuthorizeUrl(options));
-};
-
-Redirect.prototype.logout = function (options) {
- windowHelper.redirect(this.authentication.buildLogoutUrl(options));
-};
-
Redirect.prototype.login = function (options, cb) {
var usernamePassword = new UsernamePassword(this.baseOptions);
- usernamePassword.login(options, function (err, data) {
+ return usernamePassword.login(options, function (err, data) {
if (err) {
return cb(err);
}
@@ -24,13 +16,9 @@ Redirect.prototype.login = function (options, cb) {
});
};
-Redirect.prototype.signup = function (options, cb) {
- this.authentication.dbConnection.signup(options, cb);
-};
-
Redirect.prototype.signupAndLogin = function (options, cb) {
var _this = this;
- this.authentication.dbConnection.signup(options, function (err) {
+ return this.client.dbConnection.signup(options, function (err) {
if (err) {
return cb(err);
}
@@ -38,14 +26,4 @@ Redirect.prototype.signupAndLogin = function (options, cb) {
});
};
-Redirect.prototype.passwordlessVerify = function (options, cb) {
- var _this = this;
- this.authentication.passwordless.verify(options, function (err) {
- if (err) {
- return cb(err);
- }
- windowHelper.redirect(_this.authentication.passwordless.buildVerifyUrl(options));
- });
-};
-
module.exports = Redirect;
diff --git a/src/web-auth/username-password.js b/src/web-auth/username-password.js
index 71fe5770..946f6695 100644
--- a/src/web-auth/username-password.js
+++ b/src/web-auth/username-password.js
@@ -31,7 +31,7 @@ UsernamePassword.prototype.login = function (options, cb) {
body = objectHelper.toSnakeCase(body, ['auth0Client']);
- this.request
+ return this.request
.post(url)
.send(body)
.end(responseHandler(cb));
diff --git a/test/authentication/ro.test.js b/test/authentication/ro.test.js
index 78b015eb..829e5cfa 100644
--- a/test/authentication/ro.test.js
+++ b/test/authentication/ro.test.js
@@ -53,7 +53,7 @@ describe('auth0.authentication', function () {
});
});
- this.auth0.ro({
+ this.auth0.loginWithResourceOwner({
username: 'the username',
password: 'the password',
connection: 'the_connection',
@@ -91,14 +91,22 @@ describe('auth0.authentication', function () {
});
});
- this.auth0.ro({
+ this.auth0.loginWithResourceOwner({
username: 'the username',
password: 'the password',
connection: 'the_connection',
scope: 'openid'
}, function (err, data) {
expect(data).to.be(undefined);
- expect(err).to.eql({ error: 'unauthorized', error_description: 'invalid username' });
+ expect(err).to.eql({
+ original: {
+ error: 'unauthorized',
+ error_description: 'invalid username'
+ },
+ code: 'unauthorized',
+ description: 'invalid username',
+ name: null
+ });
done();
});
});
@@ -131,7 +139,7 @@ describe('auth0.authentication', function () {
});
});
- this.auth0.ro({
+ this.auth0.loginWithResourceOwner({
clientID: '123',
username: 'the username',
password: 'the password',
diff --git a/test/management/management.test.js b/test/management/management.test.js
index b15c5567..1700d341 100644
--- a/test/management/management.test.js
+++ b/test/management/management.test.js
@@ -203,7 +203,7 @@ describe('auth0.Management', function () {
it('should check that userId is valid', function() {
expect(() => {
- this.auth0.linkUsers();
+ this.auth0.linkUser();
}).to.throwException(function (e) {
expect(e.message).to.be('userId parameter is not valid');
});
@@ -211,7 +211,7 @@ describe('auth0.Management', function () {
it('should check that secondaryUserToken is valid', function() {
expect(() => {
- this.auth0.linkUsers('...');
+ this.auth0.linkUser('...');
}).to.throwException(function (e) {
expect(e.message).to.be('secondaryUserToken parameter is not valid');
});
@@ -219,7 +219,7 @@ describe('auth0.Management', function () {
it('should check that cb is valid', function() {
expect(() => {
- this.auth0.linkUsers('...', '...');
+ this.auth0.linkUser('...', '...');
}).to.throwException(function (e) {
expect(e.message).to.be('cb parameter is not valid');
});
@@ -277,7 +277,7 @@ describe('auth0.Management', function () {
});
});
- this.auth0.linkUsers('twitter|191919191919191', 'the_second_token', function(err, user) {
+ this.auth0.linkUser('twitter|191919191919191', 'the_second_token', function(err, user) {
expect(err).to.be(null);
expect(user).to.eql([{
'connection': 'twitter',
diff --git a/test/web-auth/redirect.test.js b/test/web-auth/redirect.test.js
index c1cab8b1..c06f82d4 100644
--- a/test/web-auth/redirect.test.js
+++ b/test/web-auth/redirect.test.js
@@ -52,7 +52,7 @@ describe('auth0.WebAuth.redirect', function () {
});
});
- this.auth0.redirect.signup({
+ this.auth0.signup({
connection: 'the_connection',
email: 'me@example.com',
password: '123456'
@@ -165,8 +165,7 @@ describe('auth0.WebAuth.redirect', function () {
cb({
'name': 'ValidationError',
'code': 'invalid_user_password',
- 'description': 'Wrong email or password.',
- 'statusCode': 400
+ 'description': 'Wrong email or password.'
});
}
});
@@ -188,10 +187,14 @@ describe('auth0.WebAuth.redirect', function () {
scope: 'openid'
}, function (err) {
expect(err).to.eql({
+ 'original': {
+ 'name': 'ValidationError',
+ 'code': 'invalid_user_password',
+ 'description': 'Wrong email or password.'
+ },
'name': 'ValidationError',
'code': 'invalid_user_password',
- 'description': 'Wrong email or password.',
- 'statusCode': 400
+ 'description': 'Wrong email or password.'
});
done();
});
@@ -233,10 +236,14 @@ describe('auth0.WebAuth.redirect', function () {
},
cb: function (cb) {
cb({
- 'name': 'ValidationError',
- 'code': 'invalid_user_password',
- 'description': 'Wrong email or password.',
- 'statusCode': 400
+ response: {
+ body: {
+ 'name': 'ValidationError',
+ 'code': 'invalid_user_password',
+ 'description': 'Wrong email or password.'
+ },
+ 'statusCode': 400
+ }
});
}
});
@@ -274,10 +281,20 @@ describe('auth0.WebAuth.redirect', function () {
}, function (err, data) {
expect(data).to.be(undefined);
expect(err).to.eql({
+ 'original': {
+ 'response': {
+ 'body': {
+ 'name': 'ValidationError',
+ 'code': 'invalid_user_password',
+ 'description': 'Wrong email or password.'
+ },
+ 'statusCode': 400
+ }
+ },
'name': 'ValidationError',
'code': 'invalid_user_password',
'description': 'Wrong email or password.',
- 'statusCode': 400
+ 'status_code': 400
});
done();
});
@@ -300,10 +317,13 @@ describe('auth0.WebAuth.redirect', function () {
},
cb: function (cb) {
cb({
- "name":"BadRequestError",
- "code":"user_exists",
- "description":"The user already exists.",
- "statusCode":400
+ response: {
+ "statusCode":400,
+ body: {
+ "code":"user_exists",
+ "description":"The user already exists."
+ }
+ }
});
}
});
@@ -317,10 +337,19 @@ describe('auth0.WebAuth.redirect', function () {
}, function (err, data) {
expect(data).to.be(undefined);
expect(err).to.eql({
- "name":"BadRequestError",
+ original: {
+ response: {
+ "statusCode":400,
+ body: {
+ "code":"user_exists",
+ "description":"The user already exists."
+ }
+ }
+ },
+ "name":null,
"code":"user_exists",
"description":"The user already exists.",
- "statusCode":400
+ "status_code":400
});
done();
});
@@ -368,7 +397,7 @@ describe('auth0.WebAuth.redirect', function () {
});
});
- this.auth0.redirect.passwordlessVerify({
+ this.auth0.passwordlessVerify({
connection: 'the_connection',
phoneNumber: '123456',
type: 'sms',
@@ -418,7 +447,7 @@ describe('auth0.WebAuth.redirect', function () {
});
});
- this.auth0.redirect.passwordlessVerify({
+ this.auth0.passwordlessVerify({
connection: 'the_connection',
phoneNumber: '123456',
type: 'sms',
@@ -462,15 +491,20 @@ describe('auth0.WebAuth.redirect', function () {
});
});
- this.auth0.redirect.passwordlessVerify({
+ this.auth0.passwordlessVerify({
connection: 'the_connection',
phoneNumber: '123456',
type: 'sms',
verificationCode: 'abc'
}, function (err) {
expect(err).to.eql({
- error: 'some_error_code',
- error_description: 'Some error description'
+ original: {
+ error: 'some_error_code',
+ error_description: 'Some error description'
+ },
+ name: null,
+ code: 'some_error_code',
+ description: 'Some error description'
});
done();
});
@@ -490,12 +524,12 @@ describe('auth0.WebAuth.redirect', function () {
});
it('should redirect to authorize', function () {
- this.auth0.redirect.authorize({connection: 'facebook'})
+ this.auth0.login({connection: 'facebook'})
expect(global.window.location).to.be('https://me.auth0.com/authorize?client_id=...&response_type=code&redirect_uri=http%3A%2F%2Fpage.com%2Fcallback&connection=facebook');
});
it('should redirect to logout', function () {
- this.auth0.redirect.logout({redirect_to: 'http://example.com/logout'})
+ this.auth0.logout({redirect_to: 'http://example.com/logout'})
expect(global.window.location).to.be('https://me.auth0.com/v2/logout?client_id=...&redirect_to=http%3A%2F%2Fexample.com%2Flogout');
});
});