diff --git a/README.md b/README.md index 705f952bd..9db0c8cfc 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,23 @@ lock.show(); lock.show({allowedConnections: ["twitter", "facebook"]}) ``` +### resumeAuth(hash, callback) + +If you set the [auth.autoParseHash](#authentication-options) option to `false`, you'll need to call this method to complete the authentication flow. This method is useful when you're using a client-side router that uses a `#` to handle urls (angular2 with `useHash` or react-router with `hashHistory`). +- **hash {String}**: The hash fragment received from the redirect. +- **callback {Function}**: Will be invoked after the parse is done. Has an error (if any) as the first argument and the authentication result as the second one. If there is no hash available, both arguments will be `null`. + +#### Example + +```js +lock.resumeAuth(hash, function(error, authResult) { + if (error) { + alert("Could not parse hash"); + } + console.log(authResult.accessToken); +}); +``` + ### Customization The appearance of the widget and the mechanics of authentication can be customized with an `options` object which has one or more of the following properties. Each method that opens the dialog can take an `options` object as its first argument. @@ -193,6 +210,7 @@ Authentication options are grouped in the `auth` property of the `options` objec var options = { auth: { params: {param1: "value1"}, + autoParseHash: true, redirect: true, redirectUrl: "some url", responseMode: "form_post", @@ -206,6 +224,7 @@ var options = { ``` - **params {Object}**: Specifies extra parameters that will be sent when starting a login. Defaults to `{}`. +- **autoParseHash {Boolean}**: When set to `true`, Lock will parse the `window.location.hash` string when instantiated. If set to `false`, you'll have to manually resume authentication using the [resumeAuth](#resumeauthhash-callback) method. - **redirect {Boolean}**: When set to `true`, the default, _redirect mode_ will be used. Otherwise, _popup mode_ is chosen. See [below](#popup-mode) for more details. - **redirectUrl {String}**: The url Auth0 will redirect back after authentication. Defaults to the empty string `""` (no redirect URL). - **responseMode {String}**: Should be set to `"form_post"` if you want the code or the token to be transmitted via an HTTP POST request to the `redirectUrl` instead of being included in its query or fragment parts. Otherwise, it should be ommited. diff --git a/src/core.js b/src/core.js index 038e35dfc..97b47f47c 100644 --- a/src/core.js +++ b/src/core.js @@ -4,6 +4,7 @@ import { remove, render } from './ui/box'; import webAPI from './core/web_api'; import { closeLock, + resumeAuth, handleAuthCallback, openLock, removeLock, @@ -52,14 +53,13 @@ export default class Base extends EventEmitter { go(this.id); let m = setupLock(this.id, clientID, domain, options, hookRunner, emitEventFn); - this.on('newListener', (type) => { if (this.validEvents.indexOf(type) === -1) { l.emitUnrecoverableErrorEvent(m, `Invalid event "${type}".`) } }); - if (!Base.hasScheduledAuthCallback) { + if (l.auth.autoParseHash(m) && !Base.hasScheduledAuthCallback) { Base.hasScheduledAuthCallback = true; setTimeout(handleAuthCallback, 0); } @@ -136,6 +136,10 @@ export default class Base extends EventEmitter { }); } + resumeAuth(hash, callback) { + resumeAuth(hash, callback); + } + show(opts = {}) { openLock(this.id, opts); } diff --git a/src/core/actions.js b/src/core/actions.js index 0f03e7476..bfb41e594 100644 --- a/src/core/actions.js +++ b/src/core/actions.js @@ -27,36 +27,36 @@ export function setupLock(id, clientID, domain, options, hookRunner, emitEventFn } export function handleAuthCallback() { - const hash = global.location.hash; - const ms = read(getCollection, "lock"); const keepHash = ms.filter(m => !l.hashCleanup(m)).size > 0; + const callback = (error, authResult) => { + const parsed = !!(error || authResult); + if (parsed && !keepHash) { + global.location.hash = ""; + } + }; + resumeAuth(global.location.hash, callback); +} - ms.forEach(m => { - l.auth.redirect(m) && parseHash(m, hash, (result) => { - if (result && !keepHash) { - global.location.hash = ""; - } - }) - }); +export function resumeAuth(hash, callback) { + const ms = read(getCollection, "lock"); + ms.forEach(m => l.auth.redirect(m) && parseHash(m, hash, callback)); } function parseHash(m, hash, cb) { - webApi.parseHash(l.id(m), hash, function(error, parsedHash) { - + webApi.parseHash(l.id(m), hash, function(error, authResult) { if (error) { l.emitHashParsedEvent(m, error); } else { - l.emitHashParsedEvent(m, parsedHash); + l.emitHashParsedEvent(m, authResult); } if (error) { l.emitAuthorizationErrorEvent(m, error); - } else if (parsedHash) { - l.emitAuthenticatedEvent(m, parsedHash); + } else if (authResult) { + l.emitAuthenticatedEvent(m, authResult); } - - cb(!!(error || parsedHash)) + cb(error, authResult); }); } diff --git a/src/core/index.js b/src/core/index.js index 83d3dc24c..fc5fd0a9c 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -197,6 +197,7 @@ const { get: getAuthAttribute } = dataFns(["core", "auth"]); export const auth = { connectionScopes: m => getAuthAttribute(m, "connectionScopes"), params: m => tget(m, "authParams") || getAuthAttribute(m, "params"), + autoParseHash: lock => getAuthAttribute(lock, "autoParseHash"), redirect: lock => getAuthAttribute(lock, "redirect"), redirectUrl: lock => getAuthAttribute(lock, "redirectUrl"), responseType: lock => getAuthAttribute(lock, "responseType"), @@ -209,6 +210,7 @@ function extractAuthOptions(options) { audience, connectionScopes, params, + autoParseHash, redirect, redirectUrl, responseMode, @@ -227,6 +229,7 @@ function extractAuthOptions(options) { params = typeof params === "object" ? params : {}; // by default is null because we need to know if it was set when we curate the responseType redirectUrl = typeof redirectUrl === "string" && redirectUrl ? redirectUrl : null; + autoParseHash = typeof autoParseHash === "boolean" ? autoParseHash : true; redirect = typeof redirect === "boolean" ? redirect : true; responseMode = typeof responseMode === "string" ? responseMode : undefined; state = typeof state === "string" ? state : undefined; @@ -255,6 +258,7 @@ function extractAuthOptions(options) { audience, connectionScopes, params, + autoParseHash, redirect, redirectUrl, responseMode,