Skip to content

Commit

Permalink
Add resumeAuth method and autoParseHash flag (#790)
Browse files Browse the repository at this point in the history
When Lock redirects to the redirect url, it puts the params after a # (eg: #id_token=foo&access_token=bar. This causes some issues with client side routers that use # to handle urls. An example is auth0-samples/auth0-angularjs2-systemjs-sample#40.

This PR adds an option to prevent parsing the hash when you instantiate lock (disableParseHashOnInitialization) and adds the resumeAuth method to resume the authentication steps (including all the events)
  • Loading branch information
luisrudge authored and hzalaz committed Jan 11, 2017
1 parent e5a9986 commit f0ae02a
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 18 deletions.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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",
Expand All @@ -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.
Expand Down
8 changes: 6 additions & 2 deletions src/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { remove, render } from './ui/box';
import webAPI from './core/web_api';
import {
closeLock,
resumeAuth,
handleAuthCallback,
openLock,
removeLock,
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -136,6 +136,10 @@ export default class Base extends EventEmitter {
});
}

resumeAuth(hash, callback) {
resumeAuth(hash, callback);
}

show(opts = {}) {
openLock(this.id, opts);
}
Expand Down
32 changes: 16 additions & 16 deletions src/core/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
}

Expand Down
4 changes: 4 additions & 0 deletions src/core/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand All @@ -209,6 +210,7 @@ function extractAuthOptions(options) {
audience,
connectionScopes,
params,
autoParseHash,
redirect,
redirectUrl,
responseMode,
Expand All @@ -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;
Expand Down Expand Up @@ -255,6 +258,7 @@ function extractAuthOptions(options) {
audience,
connectionScopes,
params,
autoParseHash,
redirect,
redirectUrl,
responseMode,
Expand Down

0 comments on commit f0ae02a

Please sign in to comment.