Repository: auth0/nextjs-auth0
Pull request #823 (2022-09-20 10:15:44)

[SDK-3559] Default error handler

- [ ] All new/changed/fixed functionality is covered by tests (or N/A)
- [ ] I have added documentation for all new/changed functionality (or N/A)

### 📋 Changes

Add a default `onError` handler and set the default handler to just print the status (and log the error)

### 🎯 Testing

```bash
$ npm run start:kitchen-sink
# Visit http://localhost:api/auth/callback?error=foo&error_description=bar
```


Patch:
diff --git a/V2_MIGRATION_GUIDE.md b/V2_MIGRATION_GUIDE.md
index 97f2f4b4..f2fffd1a 100644
--- a/V2_MIGRATION_GUIDE.md
+++ b/V2_MIGRATION_GUIDE.md
@@ -7,6 +7,7 @@ Guide to migrating from `1.x` to `2.x`
 - [`getServerSidePropsWrapper` has been removed](#getserversidepropswrapper-has-been-removed)
 - [Profile API route no longer returns a 401](#profile-api-route-no-longer-returns-a-401)
 - [The ID token is no longer stored by default](#the-id-token-is-no-longer-stored-by-default)
+- [Override default error handler](#override-default-error-handler)
 
 ## `getSession` now returns a `Promise`
 
@@ -113,3 +114,45 @@ Previously the ID token would be stored in the session cookie, making the cookie
 Now the SDK will not store it by default. If you had been using hooks to strip it away, you can safely remove those.
 
 You can choose to store it by setting either the `session.storeIDToken` config property or the `AUTH0_SESSION_STORE_ID_TOKEN` environment variable to `true`.
+
+## Override default error handler
+
+You can now set the default error handler for the auth routes in a single place.
+
+```js
+export default handleAuth({
+  async login(req, res) {
+    try {
+      await handleLogin(req, res);
+    } catch (error) {
+      errorLogger(error);
+      res.status(error.status || 500).end();
+    }
+  },
+  async callback(req, res) {
+    try {
+      await handleLogin(req, res);
+    } catch (error) {
+      errorLogger(error);
+      res.status(error.status || 500).end();
+    }
+  }
+  // ...
+});
+```
+
+### After
+
+```js
+export default handleAuth({
+  onError(req, res, error) {
+    errorLogger(error);
+    // You can finish the response yourself if you want to customize
+    // the status code or redirect the user
+    // res.writeHead(302, {
+    //     Location: '/custom-error-page'
+    // });
+    // res.end();
+  }
+});
+```
diff --git a/examples/kitchen-sink-example/pages/api/auth/[auth0].ts b/examples/kitchen-sink-example/pages/api/auth/[auth0].ts
index 304b4012..1511a73e 100644
--- a/examples/kitchen-sink-example/pages/api/auth/[auth0].ts
+++ b/examples/kitchen-sink-example/pages/api/auth/[auth0].ts
@@ -1,3 +1,8 @@
 import { handleAuth } from '@auth0/nextjs-auth0';
 
-export default handleAuth();
+export default handleAuth({
+  onError(req, res, error) {
+    console.error(error);
+    res.status(error.status || 500).end('Check the console for the error');
+  }
+});
diff --git a/package.json b/package.json
index 26f5a172..e9d61a3f 100644
--- a/package.json
+++ b/package.json
@@ -138,7 +138,6 @@
       "!<rootDir>/src/index.browser.ts",
       "!<rootDir>/src/middleware.ts",
       "!<rootDir>/src/instance.ts",
-      "!<rootDir>/src/handlers/auth.ts",
       "!<rootDir>/src/auth0-session/config.ts",
       "!<rootDir>/src/auth0-session/index.ts",
       "!<rootDir>/src/auth0-session/session-cache.ts"
diff --git a/src/handlers/auth.ts b/src/handlers/auth.ts
index f48ca787..4b22ee74 100644
--- a/src/handlers/auth.ts
+++ b/src/handlers/auth.ts
@@ -3,6 +3,7 @@ import { HandleLogout } from './logout';
 import { HandleCallback } from './callback';
 import { HandleProfile } from './profile';
 import { NextApiHandler, NextApiRequest, NextApiResponse } from 'next';
+import { HandlerError } from '../utils/errors';
 
 /**
  * If you want to add some custom behavior to the default auth handlers, you can pass in custom handlers for
@@ -36,6 +37,7 @@ export interface Handlers {
   logout: HandleLogout;
   callback: HandleCallback;
   profile: HandleProfile;
+  onError: OnError;
 }
 
 /**
@@ -63,19 +65,15 @@ export interface Handlers {
  */
 export type HandleAuth = (userHandlers?: Partial<Handlers>) => NextApiHandler;
 
+export type OnError = (req: NextApiRequest, res: NextApiResponse, error: HandlerError) => Promise<void> | void;
+
 /**
  * @ignore
  */
-const wrapErrorHandling =
-  (fn: NextApiHandler): NextApiHandler =>
-  async (req: NextApiRequest, res: NextApiResponse): Promise<void> => {
-    try {
-      await fn(req, res);
-    } catch (error) {
-      console.error(error);
-      res.status(error.status || 500).end(error.message);
-    }
-  };
+const defaultOnError: OnError = (_req, res, error) => {
+  console.error(error);
+  res.status(error.status || 500).end();
+};
 
 /**
  * @ignore
@@ -91,32 +89,40 @@ export default function handlerFactory({
   handleCallback: HandleCallback;
   handleProfile: HandleProfile;
 }): HandleAuth {
-  return (userHandlers: Partial<Handlers> = {}): NextApiHandler => {
+  return ({ onError, ...handlers }: Partial<Handlers> = {}): NextApiHandler<void> => {
     const { login, logout, callback, profile } = {
-      login: wrapErrorHandling(handleLogin),
-      logout: wrapErrorHandling(handleLogout),
-      callback: wrapErrorHandling(handleCallback),
-      profile: wrapErrorHandling(handleProfile),
-      ...userHandlers
+      login: handleLogin,
+      logout: handleLogout,
+      callback: handleCallback,
+      profile: handleProfile,
+      ...handlers
     };
     return async (req, res): Promise<void> => {
       let {
         query: { auth0: route }
       } = req;
 
-      route = Array.isArray(route) ? route[0] : route;
+      route = Array.isArray(route) ? route[0] : /* c8 ignore next */ route;
 
-      switch (route) {
-        case 'login':
-          return login(req, res) as void;
-        case 'logout':
-          return logout(req, res) as void;
-        case 'callback':
-          return callback(req, res) as void;
-        case 'me':
-          return profile(req, res) as void;
-        default:
-          res.status(404).end();
+      try {
+        switch (route) {
+          case 'login':
+            return await login(req, res);
+          case 'logout':
+            return await logout(req, res);
+          case 'callback':
+            return await callback(req, res);
+          case 'me':
+            return await profile(req, res);
+          default:
+            res.status(404).end();
+        }
+      } catch (error) {
+        await (onError || defaultOnError)(req, res, error);
+        if (!res.finished) {
+          // 200 is the default, so we assume it has not been set in the custom error handler if it equals 200
+          res.status(res.statusCode === 200 ? 500 : res.statusCode).end();
+        }
       }
     };
   };
diff --git a/src/handlers/index.ts b/src/handlers/index.ts
index f984698b..a059ed4a 100644
--- a/src/handlers/index.ts
+++ b/src/handlers/index.ts
@@ -2,4 +2,4 @@ export { default as callbackHandler, HandleCallback, CallbackOptions, AfterCallb
 export { default as loginHandler, HandleLogin, LoginOptions, GetLoginState } from './login';
 export { default as logoutHandler, HandleLogout, LogoutOptions } from './logout';
 export { default as profileHandler, HandleProfile, ProfileOptions, AfterRefetch } from './profile';
-export { default as handlerFactory, Handlers, HandleAuth } from './auth';
+export { default as handlerFactory, Handlers, HandleAuth, OnError } from './auth';
diff --git a/src/index.ts b/src/index.ts
index 03548181..f22cb545 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -25,7 +25,8 @@ import {
   ProfileOptions,
   CallbackOptions,
   AfterCallback,
-  AfterRefetch
+  AfterRefetch,
+  OnError
 } from './handlers';
 import {
   sessionFactory,
@@ -174,6 +175,7 @@ export {
   LoginOptions,
   LogoutOptions,
   GetLoginState,
-  InitAuth0
+  InitAuth0,
+  OnError
 };
 /* c8 ignore stop */


Test patch:
diff --git a/tests/fixtures/global.d.ts b/tests/fixtures/global.d.ts
new file mode 100644
index 00000000..e56d1d25
--- /dev/null
+++ b/tests/fixtures/global.d.ts
@@ -0,0 +1,17 @@
+declare global {
+  namespace NodeJS {
+    interface Global {
+      getSession?: Function;
+      updateUser?: Function;
+      handleAuth?: Function;
+      withApiAuthRequired?: Function;
+      withPageAuthRequired?: Function;
+      withPageAuthRequiredCSR?: Function;
+      getAccessToken?: Function;
+      asyncProps?: boolean;
+      onError?: Function;
+    }
+  }
+}
+
+export {};
diff --git a/tests/fixtures/setup.ts b/tests/fixtures/setup.ts
index 8c163575..0cda47b2 100644
--- a/tests/fixtures/setup.ts
+++ b/tests/fixtures/setup.ts
@@ -1,3 +1,5 @@
+import { IncomingMessage, ServerResponse } from 'http';
+import { NextApiRequest, NextApiResponse } from 'next';
 import nock from 'nock';
 import { CookieJar } from 'tough-cookie';
 import {
@@ -10,14 +12,14 @@ import {
   initAuth0,
   AccessTokenRequest,
   Claims,
-  GetAccessTokenResult
+  OnError,
+  Handlers
 } from '../../src';
 import { codeExchange, discovery, jwksEndpoint, userInfo } from './oidc-nocks';
 import { jwks, makeIdToken } from '../auth0-session/fixtures/cert';
 import { start, stop } from './server';
 import { encodeState } from '../../src/auth0-session/hooks/get-login-state';
 import { post, toSignedCookieJar } from '../auth0-session/fixtures/helpers';
-import { NextApiRequest, NextApiResponse } from 'next';
 
 export type SetupOptions = {
   idTokenClaims?: Claims;
@@ -27,12 +29,18 @@ export type SetupOptions = {
   profileOptions?: ProfileOptions;
   withPageAuthRequiredOptions?: WithPageAuthRequiredOptions;
   getAccessTokenOptions?: AccessTokenRequest;
+  onError?: OnError;
   discoveryOptions?: Record<string, string>;
   userInfoPayload?: Record<string, string>;
   userInfoToken?: string;
   asyncProps?: boolean;
 };
 
+const defaultOnError: OnError = (_req, res, error) => {
+  res.statusMessage = error.message;
+  res.status(error.status || 500).end(error.message);
+};
+
 export const setup = async (
   config: ConfigParameters,
   {
@@ -42,6 +50,7 @@ export const setup = async (
     loginOptions,
     profileOptions,
     withPageAuthRequiredOptions,
+    onError = defaultOnError,
     getAccessTokenOptions,
     discoveryOptions,
     userInfoPayload = {},
@@ -65,62 +74,44 @@ export const setup = async (
     withApiAuthRequired,
     withPageAuthRequired
   } = await initAuth0(config);
-  (global as any).handleAuth = handleAuth.bind(null, {
-    async callback(req, res) {
-      try {
-        await handleCallback(req, res, callbackOptions);
-      } catch (error) {
-        res.statusMessage = error.message;
-        res.status(error.status || 500).end(error.message);
-      }
-    },
-    async login(req, res) {
-      try {
-        await handleLogin(req, res, loginOptions);
-      } catch (error) {
-        res.statusMessage = error.message;
-        res.status(error.status || 500).end(error.message);
-      }
-    },
-    async logout(req, res) {
-      try {
-        await handleLogout(req, res, logoutOptions);
-      } catch (error) {
-        res.status(error.status || 500).end(error.message);
-      }
-    },
-    async profile(req, res) {
-      try {
-        await handleProfile(req, res, profileOptions);
-      } catch (error) {
-        res.statusMessage = error.message;
-        res.status(error.status || 500).end(error.message);
-      }
-    }
-  });
-
-  (global as any).getSession = getSession;
-  (global as any).updateUser = updateUser;
-  (global as any).withApiAuthRequired = withApiAuthRequired;
-  (global as any).withPageAuthRequired = (): any => withPageAuthRequired(withPageAuthRequiredOptions);
-  (global as any).withPageAuthRequiredCSR = withPageAuthRequired;
-  (global as any).getAccessToken = (req: NextApiRequest, res: NextApiResponse): Promise<GetAccessTokenResult> =>
+  const handlers: Partial<Handlers> = { onError };
+  if (callbackOptions) {
+    handlers.callback = (req, res) => handleCallback(req, res, callbackOptions);
+  }
+  if (loginOptions) {
+    handlers.login = (req, res) => handleLogin(req, res, loginOptions);
+  }
+  if (logoutOptions) {
+    handlers.logout = (req, res) => handleLogout(req, res, logoutOptions);
+  }
+  if (profileOptions) {
+    handlers.profile = (req, res) => handleProfile(req, res, profileOptions);
+  }
+  global.handleAuth = handleAuth.bind(null, handlers);
+  global.getSession = getSession;
+  global.updateUser = updateUser;
+  global.withApiAuthRequired = withApiAuthRequired;
+  global.withPageAuthRequired = (): any => withPageAuthRequired(withPageAuthRequiredOptions);
+  global.withPageAuthRequiredCSR = withPageAuthRequired;
+  global.getAccessToken = (req: IncomingMessage | NextApiRequest, res: ServerResponse | NextApiResponse) =>
     getAccessToken(req, res, getAccessTokenOptions);
-  (global as any).asyncProps = asyncProps;
+  global.onError = onError;
+  global.asyncProps = asyncProps;
   return start();
 };
 
 export const teardown = async (): Promise<void> => {
   nock.cleanAll();
   await stop();
-  delete (global as any).getSession;
-  delete (global as any).updateUser;
-  delete (global as any).handleAuth;
-  delete (global as any).withApiAuthRequired;
-  delete (global as any).withPageAuthRequired;
-  delete (global as any).withPageAuthRequiredCSR;
-  delete (global as any).getAccessToken;
-  delete (global as any).asyncProps;
+  delete global.getSession;
+  delete global.updateUser;
+  delete global.handleAuth;
+  delete global.withApiAuthRequired;
+  delete global.withPageAuthRequired;
+  delete global.withPageAuthRequiredCSR;
+  delete global.getAccessToken;
+  delete global.onError;
+  delete global.asyncProps;
 };
 
 export const login = async (baseUrl: string): Promise<CookieJar> => {
diff --git a/tests/fixtures/test-app/pages/api/access-token.ts b/tests/fixtures/test-app/pages/api/access-token.ts
index 6ee4d90e..001d7750 100644
--- a/tests/fixtures/test-app/pages/api/access-token.ts
+++ b/tests/fixtures/test-app/pages/api/access-token.ts
@@ -2,7 +2,7 @@ import { NextApiRequest, NextApiResponse } from 'next';
 
 export default async function accessTokenHandler(req: NextApiRequest, res: NextApiResponse): Promise<void> {
   try {
-    const json = await (global as any).getAccessToken(req, res);
+    const json = await global.getAccessToken?.(req, res);
     res.status(200).json(json);
   } catch (error) {
     res.statusMessage = error.message;
diff --git a/tests/fixtures/test-app/pages/api/auth/[...auth0].ts b/tests/fixtures/test-app/pages/api/auth/[...auth0].ts
index d95a4c05..ca9702e6 100644
--- a/tests/fixtures/test-app/pages/api/auth/[...auth0].ts
+++ b/tests/fixtures/test-app/pages/api/auth/[...auth0].ts
@@ -1,1 +1,1 @@
-export default (global as any).handleAuth();
+export default (...args: any) => global.handleAuth?.()(...args);
diff --git a/tests/fixtures/test-app/pages/api/protected.ts b/tests/fixtures/test-app/pages/api/protected.ts
index 090d4f67..6bf27ab1 100644
--- a/tests/fixtures/test-app/pages/api/protected.ts
+++ b/tests/fixtures/test-app/pages/api/protected.ts
@@ -1,8 +1,5 @@
 import { NextApiRequest, NextApiResponse } from 'next';
 
-export default (global as any).withApiAuthRequired(function protectedApiRoute(
-  _req: NextApiRequest,
-  res: NextApiResponse
-) {
+export default global.withApiAuthRequired?.(function protectedApiRoute(_req: NextApiRequest, res: NextApiResponse) {
   res.status(200).json({ foo: 'bar' });
 });
diff --git a/tests/fixtures/test-app/pages/api/session.ts b/tests/fixtures/test-app/pages/api/session.ts
index e451f9e8..9c88f9ed 100644
--- a/tests/fixtures/test-app/pages/api/session.ts
+++ b/tests/fixtures/test-app/pages/api/session.ts
@@ -1,6 +1,6 @@
 import { NextApiRequest, NextApiResponse } from 'next';
 
 export default async function sessionHandler(req: NextApiRequest, res: NextApiResponse) {
-  const json = await (global as any).getSession(req, res);
+  const json = await global.getSession?.(req, res);
   res.status(200).json(json);
 }
diff --git a/tests/fixtures/test-app/pages/api/update-user.ts b/tests/fixtures/test-app/pages/api/update-user.ts
index ce8f82ac..e48b4b7e 100644
--- a/tests/fixtures/test-app/pages/api/update-user.ts
+++ b/tests/fixtures/test-app/pages/api/update-user.ts
@@ -1,8 +1,8 @@
 import { NextApiRequest, NextApiResponse } from 'next';
 
 export default async function sessionHandler(req: NextApiRequest, res: NextApiResponse) {
-  const session = await (global as any).getSession(req, res);
+  const session = await global.getSession?.(req, res);
   const updated = { ...session?.user, ...req.body?.user };
-  await (global as any).updateUser(req, res, updated);
+  await global.updateUser?.(req, res, updated);
   res.status(200).json(updated);
 }
diff --git a/tests/fixtures/test-app/pages/csr-protected.tsx b/tests/fixtures/test-app/pages/csr-protected.tsx
index 5e4ec646..0978f503 100644
--- a/tests/fixtures/test-app/pages/csr-protected.tsx
+++ b/tests/fixtures/test-app/pages/csr-protected.tsx
@@ -3,7 +3,7 @@ import { NextPageContext } from 'next';
 
 // eslint-disable-next-line react/prop-types
 export default function protectedPage(): React.ReactElement {
-  return (global as any).withPageAuthRequiredCSR(() => <div>Protected Page</div>);
+  return global.withPageAuthRequiredCSR?.(() => <div>Protected Page</div>);
 }
 
-export const getServerSideProps = (ctx: NextPageContext): any => (global as any).withPageAuthRequired()(ctx);
+export const getServerSideProps = (ctx: NextPageContext): any => global.withPageAuthRequired?.()(ctx);
diff --git a/tests/fixtures/test-app/pages/global.d.ts b/tests/fixtures/test-app/pages/global.d.ts
new file mode 100644
index 00000000..7ded08be
--- /dev/null
+++ b/tests/fixtures/test-app/pages/global.d.ts
@@ -0,0 +1,1 @@
+import '../../global';
diff --git a/tests/fixtures/test-app/pages/protected.tsx b/tests/fixtures/test-app/pages/protected.tsx
index c2867745..316b8635 100644
--- a/tests/fixtures/test-app/pages/protected.tsx
+++ b/tests/fixtures/test-app/pages/protected.tsx
@@ -5,4 +5,4 @@ export default function protectedPage({ user }: { user?: { sub: string } }): Rea
   return <div>Protected Page {user ? user.sub : ''}</div>;
 }
 
-export const getServerSideProps = (ctx: NextPageContext): any => (global as any).withPageAuthRequired()(ctx);
+export const getServerSideProps = (ctx: NextPageContext): any => global.withPageAuthRequired?.()(ctx);
diff --git a/tests/handlers/auth.test.ts b/tests/handlers/auth.test.ts
new file mode 100644
index 00000000..1be1d602
--- /dev/null
+++ b/tests/handlers/auth.test.ts
@@ -0,0 +1,70 @@
+import { IncomingMessage, ServerResponse } from 'http';
+import { ArgumentsOf } from 'ts-jest';
+import { withoutApi } from '../fixtures/default-settings';
+import { setup, teardown } from '../fixtures/setup';
+import { get } from '../auth0-session/fixtures/helpers';
+import { initAuth0, OnError } from '../../src';
+
+const handlerError = (status = 400, error = 'foo', error_description = 'bar') =>
+  expect.objectContaining({
+    status,
+    cause: expect.objectContaining({ error, error_description })
+  });
+
+describe('auth handler', () => {
+  afterEach(teardown);
+
+  test('accept custom error handler', async () => {
+    const onError = jest.fn<void, ArgumentsOf<OnError>>((_req, res) => res.end());
+    const baseUrl = await setup(withoutApi, { onError });
+    await get(baseUrl, '/api/auth/callback?error=foo&error_description=bar');
+    expect(onError).toHaveBeenCalledWith(expect.any(IncomingMessage), expect.any(ServerResponse), handlerError());
+  });
+
+  test('use default error handler', async () => {
+    const baseUrl = await setup(withoutApi);
+    global.handleAuth = (await initAuth0(withoutApi)).handleAuth;
+    delete global.onError;
+    jest.spyOn(console, 'error').mockImplementation(() => {});
+    await expect(get(baseUrl, '/api/auth/callback?error=foo&error_description=bar')).rejects.toThrow('Bad Request');
+    expect(console.error).toHaveBeenCalledWith(new Error('Callback handler failed. CAUSE: foo (bar)'));
+  });
+
+  test('finish response if custom error does not', async () => {
+    const onError = jest.fn();
+    const baseUrl = await setup(withoutApi);
+    global.handleAuth = (await initAuth0(withoutApi)).handleAuth.bind(null, { onError });
+    await expect(
+      get(baseUrl, '/api/auth/callback?error=foo&error_description=bar', { fullResponse: true })
+    ).rejects.toThrow('Internal Server Error');
+    expect(onError).toHaveBeenCalledWith(expect.any(IncomingMessage), expect.any(ServerResponse), handlerError());
+  });
+
+  test('finish response with custom error status', async () => {
+    const onError = jest.fn<void, ArgumentsOf<OnError>>((_req, res) => res.status(418));
+    const baseUrl = await setup(withoutApi);
+    global.handleAuth = (await initAuth0(withoutApi)).handleAuth.bind(null, { onError });
+    await expect(
+      get(baseUrl, '/api/auth/callback?error=foo&error_description=bar', { fullResponse: true })
+    ).rejects.toThrow("I'm a Teapot");
+    expect(onError).toHaveBeenCalledWith(expect.any(IncomingMessage), expect.any(ServerResponse), handlerError());
+  });
+
+  test('return 500 for unexpected error', async () => {
+    const baseUrl = await setup(withoutApi);
+    global.handleAuth = (await initAuth0(withoutApi)).handleAuth;
+    delete global.onError;
+    jest.spyOn(console, 'error').mockImplementation((error) => {
+      delete error.status;
+    });
+    await expect(get(baseUrl, '/api/auth/callback?error=foo&error_description=bar')).rejects.toThrow(
+      'Internal Server Error'
+    );
+  });
+
+  test('return 404 for unknown routes', async () => {
+    const baseUrl = await setup(withoutApi);
+    global.handleAuth = (await initAuth0(withoutApi)).handleAuth;
+    await expect(get(baseUrl, '/api/auth/foo')).rejects.toThrow('Not Found');
+  });
+});
diff --git a/tests/handlers/logout.test.ts b/tests/handlers/logout.test.ts
index 4a980097..3d197d89 100644
--- a/tests/handlers/logout.test.ts
+++ b/tests/handlers/logout.test.ts
@@ -1,18 +1,8 @@
 import { parse } from 'cookie';
-import { parse as parseUrl, URL } from 'url';
+import { parse as parseUrl } from 'url';
 import { withoutApi } from '../fixtures/default-settings';
 import { get } from '../auth0-session/fixtures/helpers';
 import { setup, teardown, login } from '../fixtures/setup';
-import { IncomingMessage } from 'http';
-
-jest.mock('../../src/utils/assert', () => ({
-  assertReqRes(req: IncomingMessage) {
-    if (req.url?.includes('error=')) {
-      const url = new URL(req.url, 'http://example.com');
-      throw new Error(url.searchParams.get('error') as string);
-    }
-  }
-}));
 
 describe('logout handler', () => {
   afterEach(teardown);
@@ -99,11 +89,4 @@ describe('logout handler', () => {
       Path: '/'
     });
   });
-
-  test('should escape html in error message', async () => {
-    const baseUrl = await setup(withoutApi);
-    const res = await fetch(`${baseUrl}/api/auth/logout?error=%3Cscript%3Ealert(%27xss%27)%3C%2Fscript%3E`);
-
-    expect(await res.text()).toEqual('Logout handler failed. CAUSE: &lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;');
-  });
 });
diff --git a/tests/handlers/profile.test.ts b/tests/handlers/profile.test.ts
index 504951a6..90fad9e5 100644
--- a/tests/handlers/profile.test.ts
+++ b/tests/handlers/profile.test.ts
@@ -5,17 +5,6 @@ import { get } from '../auth0-session/fixtures/helpers';
 import { setup, teardown, login } from '../fixtures/setup';
 import { Session, AfterCallback } from '../../src';
 import { makeIdToken } from '../auth0-session/fixtures/cert';
-import { IncomingMessage } from 'http';
-import { URL } from 'url';
-
-jest.mock('../../src/utils/assert', () => ({
-  assertReqRes(req: IncomingMessage) {
-    if (req.url?.includes('error=')) {
-      const url = new URL(req.url, 'http://example.com');
-      throw new Error(url.searchParams.get('error') as string);
-    }
-  }
-}));
 
 describe('profile handler', () => {
   afterEach(teardown);
@@ -153,13 +142,4 @@ describe('profile handler', () => {
 
     await expect(get(baseUrl, '/api/auth/me', { cookieJar })).rejects.toThrowError('some validation error');
   });
-
-  test('should escape html in error message', async () => {
-    const baseUrl = await setup(withoutApi);
-    const res = await fetch(`${baseUrl}/api/auth/me?error=%3Cscript%3Ealert(%27xss%27)%3C%2Fscript%3E`);
-
-    expect(await res.text()).toEqual(
-      'Profile handler failed. CAUSE: &lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;'
-    );
-  });
 });