Repository: auth0/nextjs-auth0
Pull request #137 (2020-06-30 17:16:01)

Bump express-jwt from 5.3.1 to 6.0.0 in /examples/sample-api
Bumps [express-jwt](https://github.com/auth0/express-jwt) from 5.3.1 to 6.0.0.
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/auth0/express-jwt/commit/678f3b0e812d86b399b925f069105fc37eecde5b"><code>678f3b0</code></a> 6.0.0</li>
<li><a href="https://github.com/auth0/express-jwt/commit/7ecab5f8f0cab5297c2b863596566eb0c019cdef"><code>7ecab5f</code></a> Merge pull request from GHSA-6g6m-m6h5-w9gf</li>
<li><a href="https://github.com/auth0/express-jwt/commit/304a1c5968aed7c4c520035426fc09142156669d"><code>304a1c5</code></a> Made algorithms mandatory</li>
<li><a href="https://github.com/auth0/express-jwt/commit/e9ed6d240d945fca8f8911c1f1d743dfe3f1f8e3"><code>e9ed6d2</code></a> 5.3.3</li>
<li><a href="https://github.com/auth0/express-jwt/commit/8662579f1af7ba1d8b6a35718243bd719600a23f"><code>8662579</code></a> Make clearer sections in the Readme</li>
<li><a href="https://github.com/auth0/express-jwt/commit/d3e86bffb6f0c629cbb95e9b27432e4860d8bc5a"><code>d3e86bf</code></a> Update README.md</li>
<li><a href="https://github.com/auth0/express-jwt/commit/c5d841966b70584fa51f766d7cb2b17ae1db6681"><code>c5d8419</code></a> Add a note about OAuth2 bearer tokens</li>
<li><a href="https://github.com/auth0/express-jwt/commit/888f0e9d2cb3026a50b2812a0eebe7a5d5011744"><code>888f0e9</code></a> Update Readme and use a consistent JS style for code examples</li>
<li><a href="https://github.com/auth0/express-jwt/commit/659101493f1d8abe06467c00431f49ba9e761f35"><code>6591014</code></a> 5.3.2</li>
<li><a href="https://github.com/auth0/express-jwt/commit/f4f4d1d6bf78d498688f1b1936551546715d01e9"><code>f4f4d1d</code></a> fix license field</li>
<li>Additional commits viewable in <a href="https://github.com/auth0/express-jwt/compare/v5.3.1...v6.0.0">compare view</a></li>
</ul>
</details>
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by <a href="https://www.npmjs.com/~yacine-b">yacine-b</a>, a new releaser for express-jwt since your current version.</p>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=express-jwt&package-manager=npm_and_yarn&previous-version=5.3.1&new-version=6.0.0)](https://help.github.com/articles/configuring-automated-security-fixes)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
- `@dependabot use these labels` will set the current labels as the default for future PRs for this repo and language
- `@dependabot use these reviewers` will set the current reviewers as the default for future PRs for this repo and language
- `@dependabot use these assignees` will set the current assignees as the default for future PRs for this repo and language
- `@dependabot use this milestone` will set the current milestone as the default for future PRs for this repo and language

You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/auth0/nextjs-auth0/network/alerts).

</details>


Patch:
diff --git a/README.md b/README.md
index 7a5e4224..7f22333e 100644
--- a/README.md
+++ b/README.md
@@ -114,7 +114,7 @@ export default async function login(req, res) {
 }
 ```
 
-> Note: This route supports providing `redirectTo` in the querystring, eg: (`/api/login?redirectTo=/profile`). The user will automatically be redirect to this URL after signing in.
+> Note: This route supports providing `redirectTo` in the query string, eg: (`/api/login?redirectTo=/profile`). The user will automatically be redirect to this URL after signing in.
 
 This will redirect the user to Auth0. After the transaction is completed Auth0 will redirect the user back to your application. This is why the callback route (`/pages/api/callback.js`) needs to be created which will create a session cookie:
 
@@ -204,6 +204,8 @@ export default async function logout(req, res) {
 }
 ```
 
+Note that the third parameter of `handleLogout` accepts an optional `returnTo` to allow request-time configuration of where to redirect the user to on logout.
+
 ### User Profile
 
 If you want to expose a route which returns the user profile to the client you can create an additional route (eg: `/pages/api/me.js`):
diff --git a/examples/sample-api/package-lock.json b/examples/sample-api/package-lock.json
index 15dbb9a2..64379411 100644
--- a/examples/sample-api/package-lock.json
+++ b/examples/sample-api/package-lock.json
@@ -335,9 +335,9 @@
       }
     },
     "express-jwt": {
-      "version": "5.3.1",
-      "resolved": "https://registry.npmjs.org/express-jwt/-/express-jwt-5.3.1.tgz",
-      "integrity": "sha512-1C9RNq0wMp/JvsH/qZMlg3SIPvKu14YkZ4YYv7gJQ1Vq+Dv8LH9tLKenS5vMNth45gTlEUGx+ycp9IHIlaHP/g==",
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/express-jwt/-/express-jwt-6.0.0.tgz",
+      "integrity": "sha512-C26y9myRjx7CyhZ+BAT3p+gQyRCoDZ7qo8plCvLDaRT6je6ALIAQknT6XLVQGFKwIy/Ux7lvM2MNap5dt0T7gA==",
       "requires": {
         "async": "^1.5.0",
         "express-unless": "^0.3.0",
diff --git a/examples/sample-api/package.json b/examples/sample-api/package.json
index 9762d215..7f890c3c 100644
--- a/examples/sample-api/package.json
+++ b/examples/sample-api/package.json
@@ -12,7 +12,7 @@
     "cors": "^2.8.5",
     "dotenv": "^8.1.0",
     "express": "^4.17.1",
-    "express-jwt": "^5.3.1",
+    "express-jwt": "^6.0.0",
     "isomorphic-unfetch": "^3.0.0",
     "jwks-rsa": "^1.6.0"
   }
diff --git a/src/handlers/logout.ts b/src/handlers/logout.ts
index 6f1328a3..a417756d 100644
--- a/src/handlers/logout.ts
+++ b/src/handlers/logout.ts
@@ -6,12 +6,12 @@ import { IOidcClientFactory } from '../utils/oidc-client';
 import CookieSessionStoreSettings from '../session/cookie-store/settings';
 import { ISessionStore } from '../session/store';
 
-function createLogoutUrl(settings: IAuth0Settings): string {
-  return (
-    `https://${settings.domain}/v2/logout?` +
-    `client_id=${settings.clientId}` +
-    `&returnTo=${encodeURIComponent(settings.postLogoutRedirectUri)}`
-  );
+export interface LogoutOptions {
+  returnTo?: string;
+}
+
+function createLogoutUrl(settings: IAuth0Settings, returnToUrl: string): string {
+  return `https://${settings.domain}/v2/logout?client_id=${settings.clientId}&returnTo=${returnToUrl}`;
 }
 
 export default function logoutHandler(
@@ -20,7 +20,7 @@ export default function logoutHandler(
   clientProvider: IOidcClientFactory,
   store: ISessionStore
 ) {
-  return async (req: NextApiRequest, res: NextApiResponse): Promise<void> => {
+  return async (req: NextApiRequest, res: NextApiResponse, options?: LogoutOptions): Promise<void> => {
     if (!req) {
       throw new Error('Request is not available');
     }
@@ -31,17 +31,18 @@ export default function logoutHandler(
 
     const session = await store.read(req);
     let endSessionUrl;
+    const returnToUrl = options?.returnTo || settings.postLogoutRedirectUri;
 
     try {
       const client = await clientProvider();
       endSessionUrl = client.endSessionUrl({
         id_token_hint: session ? session.idToken : undefined,
-        post_logout_redirect_uri: encodeURIComponent(settings.postLogoutRedirectUri)
+        post_logout_redirect_uri: returnToUrl
       });
     } catch (err) {
       if (/end_session_endpoint must be configured/.exec(err)) {
         // Use default url if end_session_endpoint is not configured
-        endSessionUrl = createLogoutUrl(settings);
+        endSessionUrl = createLogoutUrl(settings, returnToUrl);
       } else {
         throw err;
       }
diff --git a/src/instance.ts b/src/instance.ts
index d4380a21..05715bfc 100644
--- a/src/instance.ts
+++ b/src/instance.ts
@@ -5,6 +5,7 @@ import { LoginOptions } from './handlers/login';
 import { ITokenCache } from './tokens/token-cache';
 import { CallbackOptions } from './handlers/callback';
 import { ProfileOptions } from './handlers/profile';
+import { LogoutOptions } from './handlers/logout';
 import { IApiRoute } from './handlers/require-authentication';
 
 export interface ISignInWithAuth0 {
@@ -19,9 +20,9 @@ export interface ISignInWithAuth0 {
   handleCallback: (req: NextApiRequest, res: NextApiResponse, options?: CallbackOptions) => Promise<void>;
 
   /**
-   * Logout handler which will clear the local session and the Auth0 session
+   * Logout handler which will clear the local session and the Auth0 session.
    */
-  handleLogout: (req: NextApiRequest, res: NextApiResponse) => Promise<void>;
+  handleLogout: (req: NextApiRequest, res: NextApiResponse, options?: LogoutOptions) => Promise<void>;
 
   /**
    * Profile handler which return profile information about the user.


Test patch:
diff --git a/tests/handlers/logout.test.ts b/tests/handlers/logout.test.ts
index 16aa4e1e..5268af78 100644
--- a/tests/handlers/logout.test.ts
+++ b/tests/handlers/logout.test.ts
@@ -3,7 +3,7 @@ import { parse } from 'cookie';
 import { promisify } from 'util';
 
 import HttpServer from '../helpers/server';
-import logout from '../../src/handlers/logout';
+import logout, { LogoutOptions } from '../../src/handlers/logout';
 import { withoutApi } from '../helpers/default-settings';
 import CookieSessionStoreSettings from '../../src/session/cookie-store/settings';
 import { discovery } from '../helpers/oidc-nocks';
@@ -34,11 +34,18 @@ const sessionStore: ISessionStore = {
 
 describe('logout handler', () => {
   let httpServer: HttpServer;
+  let logoutHandler: any;
+  let logoutOptions: LogoutOptions | null;
 
   beforeEach((done) => {
-    httpServer = new HttpServer(
-      logout(withoutApi, new CookieSessionStoreSettings(withoutApi.session), getClient(withoutApi), sessionStore)
+    logoutHandler = logout(
+      withoutApi,
+      new CookieSessionStoreSettings(withoutApi.session),
+      getClient(withoutApi),
+      sessionStore
     );
+    logoutOptions = {};
+    httpServer = new HttpServer((req, res) => logoutHandler(req, res, logoutOptions));
     httpServer.start(done);
   });
 
@@ -62,6 +69,26 @@ describe('logout handler', () => {
     );
   });
 
+  test('should return to the custom path', async () => {
+    const customReturnTo = 'https://www.foo.bar';
+    logoutOptions = {
+      returnTo: customReturnTo
+    };
+    discovery(withoutApi);
+
+    const { statusCode, headers } = await getAsync({
+      url: httpServer.getUrl(),
+      followRedirect: false
+    });
+
+    expect(statusCode).toBe(302);
+    expect(headers.location).toBe(
+      `https://${withoutApi.domain}/v2/logout?client_id=${withoutApi.clientId}&returnTo=${encodeURIComponent(
+        customReturnTo
+      )}`
+    );
+  });
+
   test('should use end_session_endpoint if available', async () => {
     discovery(withoutApi, { end_session_endpoint: 'https://my-end-session-endpoint/logout' });
 
@@ -73,7 +100,7 @@ describe('logout handler', () => {
     expect(statusCode).toBe(302);
     expect(headers.location).toBe(
       `https://my-end-session-endpoint/logout` +
-        `?id_token_hint=my-id-token&post_logout_redirect_uri=https%253A%252F%252Fwww.acme.com`
+        `?id_token_hint=my-id-token&post_logout_redirect_uri=https%3A%2F%2Fwww.acme.com`
     );
   });