diff --git a/docs-src/silent-refresh.md b/docs-src/silent-refresh.md index b0be222c..1621208e 100644 --- a/docs-src/silent-refresh.md +++ b/docs-src/silent-refresh.md @@ -67,7 +67,6 @@ This simple implementation within silent-refresh.html is sufficient in most case var checks = [/[\?|&|#]code=/, /[\?|&|#]error=/, /[\?|&|#]token=/, /[\?|&|#]id_token=/]; function isResponse(str) { - var count = 0; if (!str) return false; for(var i=0; i ``` +The above example checks if the message in the URL (either hash or query string) is indeed a message returned with a response from an authentication provider and not an arbitrary value and then attempts to forward this message to a parent widow either by `.parent` (when this html is loaded in an iframe as a result of silent refresh) or by `.opener` (when the html is loaded into a popup during initial login) or finally using a storage event (as a fallback for complex cases, e.g. initial login in a popup with a cross-domain auth provider). + Please make sure that this file is copied to your output directory by your build task. When using the CLI you can define it as an asset for this. For this, you have to add the following line to the file ``.angular-cli.json``: ```JSON diff --git a/projects/lib/src/oauth-service.ts b/projects/lib/src/oauth-service.ts index 90ed2566..8f306883 100644 --- a/projects/lib/src/oauth-service.ts +++ b/projects/lib/src/oauth-service.ts @@ -1083,7 +1083,7 @@ export class OAuthService extends AuthConfig implements OnDestroy { return this.initLoginFlowInPopup(options); } - public initLoginFlowInPopup(options?: { height?: number; width?: number }) { + public initLoginFlowInPopup(options?: { height?: number; width?: number }): Promise { options = options || {}; return this.createLoginUrl( null, @@ -1105,6 +1105,21 @@ export class OAuthService extends AuthConfig implements OnDestroy { this.calculatePopupFeatures(options) ); let checkForPopupClosedTimer: any; + + const tryLogin = (hash: string) => { + this.tryLogin({ + customHashFragment: hash, + preventClearHashAfterLogin: true, + customRedirectUri: this.silentRefreshRedirectUri, + }).then(() => { + cleanup(); + resolve(true); + }, err => { + cleanup(); + reject(err); + }); + }; + const checkForPopupClosed = () => { if (!windowRef || windowRef.closed) { cleanup(); @@ -1122,6 +1137,7 @@ export class OAuthService extends AuthConfig implements OnDestroy { const cleanup = () => { window.clearInterval(checkForPopupClosedTimer); + window.removeEventListener('storage', storageListener); window.removeEventListener('message', listener); if (windowRef !== null) { windowRef.close(); @@ -1133,26 +1149,22 @@ export class OAuthService extends AuthConfig implements OnDestroy { const message = this.processMessageEventMessage(e); if (message && message !== null) { - this.tryLogin({ - customHashFragment: message, - preventClearHashAfterLogin: true, - customRedirectUri: this.silentRefreshRedirectUri - }).then( - () => { - cleanup(); - resolve(); - }, - err => { - cleanup(); - reject(err); - } - ); + window.removeEventListener('storage', storageListener); + tryLogin(message); } else { console.log('false event firing'); } }; + const storageListener = (event: StorageEvent) => { + if (event.key === 'auth_hash') { + window.removeEventListener('message', listener); + tryLogin(event.newValue); + } + }; + window.addEventListener('message', listener); + window.addEventListener('storage', storageListener); }); }); } diff --git a/projects/sample/src/silent-refresh.html b/projects/sample/src/silent-refresh.html index aee87120..a369b9f0 100644 --- a/projects/sample/src/silent-refresh.html +++ b/projects/sample/src/silent-refresh.html @@ -9,7 +9,6 @@ ]; function isResponse(str) { - var count = 0; if (!str) return false; for (var i = 0; i < checks.length; i++) { if (str.match(checks[i])) return true; @@ -21,7 +20,18 @@ ? location.hash : '#' + location.search; - (window.opener || window.parent).postMessage(message, location.origin); + if (window.parent && window.parent !== window) { + // if loaded as an iframe during silent refresh + window.parent.postMessage(message, location.origin); + } else if (window.opener && window.opener !== window) { + // if loaded as a popup during initial login + window.opener.postMessage(message, location.origin); + } else { + // last resort for a popup which has been through redirects and can't use window.opener + localStorage.setItem('auth_hash', message); + localStorage.removeItem('auth_hash'); + } +