Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[IAMRISK-3539] Add challenge endpoint for signup #1467

Merged
merged 1 commit into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
570 changes: 426 additions & 144 deletions dist/auth0.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dist/auth0.min.esm.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/auth0.min.esm.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dist/auth0.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/auth0.min.js.map

Large diffs are not rendered by default.

506 changes: 370 additions & 136 deletions dist/cordova-auth0-plugin.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dist/cordova-auth0-plugin.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/cordova-auth0-plugin.min.js.map

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions src/authentication/db-connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,20 @@ DBConnection.prototype.getPasswordResetChallenge = function (cb) {
.end(responseHandler(cb, { ignoreCasing: true }));
};


DBConnection.prototype.getSignupChallenge = function (cb) {
assert.check(cb, { type: 'function', message: 'cb parameter is not valid' });

if (!this.baseOptions.state) {
return cb();
}

var url = urljoin(this.baseOptions.rootUrl, 'dbconnections', 'signup', 'challenge');

return this.request
.post(url)
.send({ state: this.baseOptions.state })
.end(responseHandler(cb, { ignoreCasing: true }));
};

export default DBConnection;
3 changes: 3 additions & 0 deletions src/web-auth/captcha.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ var captchaSolved = noop;

var Flow = {
DEFAULT: 'default',
SIGNUP: 'signup',
PASSWORDLESS: 'passwordless',
PASSWORD_RESET: 'password_reset'
};
Expand Down Expand Up @@ -417,6 +418,8 @@ function render(auth0Client, flow, element, options, callback) {
auth0Client.passwordless.getChallenge(challengeCallback);
} else if (flow === Flow.PASSWORD_RESET) {
auth0Client.dbConnection.getPasswordResetChallenge(challengeCallback);
} else if (flow === Flow.SIGNUP) {
auth0Client.dbConnection.getSignupChallenge(challengeCallback);
} else {
auth0Client.getChallenge(challengeCallback);
}
Expand Down
45 changes: 37 additions & 8 deletions src/web-auth/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -642,15 +642,15 @@ WebAuth.prototype.renewAuth = function (options, cb) {
* Renews an existing session on Auth0's servers using `response_mode=web_message`
*
* Allows you to acquire a new token from Auth0 for a user who already
* has an SSO session established against Auth0 for your domain.
* If the user is not authenticated, the authentication result will be empty
* has an SSO session established against Auth0 for your domain.
* If the user is not authenticated, the authentication result will be empty
* and you'll receive an error like this: `{error: 'login_required'}`.
* The method accepts any valid OAuth2 parameters that would normally be sent to `/authorize`.
*
*
* Everything happens inside an iframe, so it will not reload your application or redirect away from it.
*
* **Important:** If you're not using the hosted login page to do social logins,
* you have to use your own [social connection keys](https://manage.auth0.com/#/connections/social).
*
* **Important:** If you're not using the hosted login page to do social logins,
* you have to use your own [social connection keys](https://manage.auth0.com/#/connections/social).
* If you use Auth0's dev keys, you'll always get `login_required` as an error when calling `checkSession`.
*
* **Important:** Because there is no redirect in this method, `responseType: 'code'` is not supported and will throw an error.
Expand All @@ -664,7 +664,7 @@ WebAuth.prototype.renewAuth = function (options, cb) {
* function(err, authResult) {
* // Authentication tokens or error
* });
*
*
* @method checkSession
* @param {Object} [options]
* @param {String} [options.clientID] the Client ID found on your Application settings page
Expand Down Expand Up @@ -1138,7 +1138,7 @@ WebAuth.prototype.passwordlessVerify = function (options, cb) {

/**
*
* Renders the captcha challenge in the provided element.
* Renders the login captcha challenge in the provided element.
* This function can only be used in the context of a Classic Universal Login Page.
*
* @method renderCaptcha
Expand All @@ -1161,6 +1161,35 @@ WebAuth.prototype.renderCaptcha = function (element, options, callback) {
return captcha.render(this.client, captcha.Flow.DEFAULT, element, options, callback);
};

/**
*
* Renders the signup captcha challenge in the provided element.
* This function can only be used in the context of a Classic Universal Login Page.
*
* @method renderSignupCaptcha
* @param {HTMLElement} element The element where the captcha needs to be rendered
* @param {Object} options The configuration options for the captcha
* @param {Object} [options.templates] An object containing templates for each captcha provider
* @param {Function} [options.templates.auth0] template function receiving the challenge and returning a string
* @param {Function} [options.templates.recaptcha_v2] template function receiving the challenge and returning a string
* @param {Function} [options.templates.recaptcha_enterprise] template function receiving the challenge and returning a string
* @param {Function} [options.templates.hcaptcha] template function receiving the challenge and returning a string
* @param {Function} [options.templates.friendly_captcha] template function receiving the challenge and returning a string
* @param {Function} [options.templates.arkose] template function receiving the challenge and returning a string
* @param {Function} [options.templates.auth0_v2] template function receiving the challenge and returning a string
* @param {Function} [options.templates.error] template function returning a custom error message when the challenge could not be fetched, receives the error as first argument
* @param {String} [options.lang=en] the ISO code of the language for the captcha provider
* @param {captchaLoadedCallback} [callback] An optional callback called after captcha is loaded
* @memberof WebAuth.prototype
*/
WebAuth.prototype.renderSignupCaptcha = function (
element,
options,
callback
) {
return captcha.render(this.client, captcha.Flow.SIGNUP, element, options, callback);
};

/**
*
* Renders the passwordless captcha challenge in the provided element.
Expand Down
90 changes: 90 additions & 0 deletions test/authentication/db-connection.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -319,4 +319,94 @@ describe('auth0.authentication', function () {
});
});
});

context('dbConnection getSignupChallenge', function () {
context('when the client does not have state', function () {
before(function () {
this.auth0 = new Authentication(this.webAuthSpy, {
domain: 'me.auth0.com',
clientID: '...',
redirectUri: 'http://page.com/callback',
responseType: 'code',
_sendTelemetry: false
});
});

it('should return nothing', function (done) {
this.auth0.dbConnection.getSignupChallenge((err, challenge) => {
expect(err).to.not.be.ok();
expect(challenge).to.not.be.ok();
done();
});
});
});

context('when the client has state', function () {
before(function () {
this.auth0 = new Authentication(this.webAuthSpy, {
domain: 'me.auth0.com',
clientID: '...',
redirectUri: 'http://page.com/callback',
responseType: 'code',
_sendTelemetry: false,
state: '123abc'
});
});

afterEach(function () {
request.post.restore();
});

it('should post state and returns the image/type', function (done) {
sinon.stub(request, 'post').callsFake(function (url) {
expect(url).to.be('https://me.auth0.com/dbconnections/signup/challenge');
return new RequestMock({
body: {
state: '123abc'
},
headers: {
'Content-Type': 'application/json'
},
cb: function (cb) {
cb(null, {
body: {
image: 'svg+yadayada',
type: 'code'
}
});
}
});
});

this.auth0.dbConnection.getSignupChallenge((err, challenge) => {
expect(err).to.not.be.ok();
expect(challenge.image).to.be('svg+yadayada');
expect(challenge.type).to.be('code');
done();
});
});

it('should return the error if network fails', function (done) {
sinon.stub(request, 'post').callsFake(function (url) {
expect(url).to.be('https://me.auth0.com/dbconnections/signup/challenge');
return new RequestMock({
body: {
state: '123abc'
},
headers: {
'Content-Type': 'application/json'
},
cb: function (cb) {
cb(new Error('error error error'));
}
});
});

this.auth0.dbConnection.getSignupChallenge((err, challenge) => {
expect(err.original.message).to.equal('error error error');
done();
});
});
});
});
});
Loading