diff --git a/README.md b/README.md index 4345b336..6f234942 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ ng add @auth0/auth0-angular - [Protect a route](#protect-a-route) - [Call an API](#call-an-api) - [Dynamic configuration](#dynamic-configuration) +- [Using multiple OAuth providers](#using-multiple-oauth-providers) ### Register the authentication module @@ -311,7 +312,7 @@ export class MyComponent { } ``` -## Dynamic Configuration +### Dynamic Configuration Instead of using `AuthModule.forRoot` to specify auth configuration, you can provide a factory function using `APP_INITIALIZER` to load your config from an external source before the auth module is loaded, and provide your configuration using `AuthClientConfig.set`: @@ -349,6 +350,19 @@ providers: [ ], ``` +### Using multiple OAuth providers + +If your application uses multiple OAuth providers, you may need to use multiple callback paths as well, one for each OAuth provider. +To ensure the SDK does not process the callback for any provider other than Auth0, configure the AuthModule by setting the `skipRedirectCallback` property as follows: + +```js +AuthModule.forRoot({ + skipRedirectCallback: window.location.pathname === '/other-callback', +}); +``` + +**Note**: In the above example, `/other-callback` is an existing route that will be called by any other OAuth provider with a `code` (or `error` in case something went wrong) and `state`. + ## Angular Universal This library makes use of the `window` object in a couple of places during initialization, as well as `sessionStorage` in the underlying Auth0 SPA SDK, and thus [will have problems](https://github.com/angular/universal/blob/master/docs/gotchas.md#window-is-not-defined) when being used in an Angular Universal project. The recommendation currently is to only import this library into a module that is to be used in the browser, and omit it from any module that is to participate in a server-side environment. diff --git a/projects/auth0-angular/src/lib/auth.config.ts b/projects/auth0-angular/src/lib/auth.config.ts index a2dd9f64..e750ed49 100644 --- a/projects/auth0-angular/src/lib/auth.config.ts +++ b/projects/auth0-angular/src/lib/auth.config.ts @@ -105,6 +105,24 @@ export interface AuthConfig { */ redirectUri?: string; + /** + * By default, if the page URL has code and state parameters, the SDK will assume they are for + * an Auth0 application and attempt to exchange the code for a token. + * In some cases the code might be for something else (e.g. another OAuth SDK). In these + * instances you can instruct the client to ignore them by setting `skipRedirectCallback`. + * + * ```js + * AuthModule.forRoot({ + * skipRedirectCallback: window.location.pathname === '/other-callback' + * }) + * ``` + * + * **Note**: In the above example, `/other-callback` is an existing route that will be called + * by any other OAuth provider with a `code` (or `error` in case when something went wrong) and `state`. + * + */ + skipRedirectCallback?: boolean; + /** * The value in seconds used to account for clock skew in JWT expirations. * Typically, this value is no more than a minute or two at maximum. diff --git a/projects/auth0-angular/src/lib/auth.service.spec.ts b/projects/auth0-angular/src/lib/auth.service.spec.ts index 90dfad4b..790a0765 100644 --- a/projects/auth0-angular/src/lib/auth.service.spec.ts +++ b/projects/auth0-angular/src/lib/auth.service.spec.ts @@ -194,6 +194,17 @@ describe('AuthService', () => { }); }); + it('should not handle the callback when skipRedirectCallback is true', (done) => { + authConfig.skipRedirectCallback = true; + + const localService = createService(); + + loaded(localService).subscribe(() => { + expect(auth0Client.handleRedirectCallback).not.toHaveBeenCalled(); + done(); + }); + }); + it('should redirect to the correct route', (done) => { const localService = createService(); diff --git a/projects/auth0-angular/src/lib/auth.service.ts b/projects/auth0-angular/src/lib/auth.service.ts index 020100a4..a2b99a23 100644 --- a/projects/auth0-angular/src/lib/auth.service.ts +++ b/projects/auth0-angular/src/lib/auth.service.ts @@ -256,11 +256,13 @@ export class AuthService implements OnDestroy { private shouldHandleCallback(): Observable { return of(this.location.path()).pipe( - map( - (search) => + map((search) => { + return ( (search.includes('code=') || search.includes('error=')) && - search.includes('state=') - ) + search.includes('state=') && + !this.configFactory.get().skipRedirectCallback + ); + }) ); }