diff --git a/docs/authentication/custom-strategies.mdx b/docs/authentication/custom-strategies.mdx index 7b96614d5d..40bda6f8e1 100644 --- a/docs/authentication/custom-strategies.mdx +++ b/docs/authentication/custom-strategies.mdx @@ -33,10 +33,12 @@ The `authenticate` function is passed the following arguments: ### Example Strategy -At its core a strategy simply takes information from the incoming request and returns a user. This is exactly how Payloads built-in strategies function. +At its core a strategy simply takes information from the incoming request and returns a user. This is exactly how Payload's built-in strategies function. + +Your `authenticate` method should return an object containing a Payload user document and any optional headers that you'd like Payload to set for you when we return a response. ```ts -import { CollectionConfig } from 'payload/types' +import { CollectionConfig } from 'payload' export const Users: CollectionConfig = { slug: 'users', @@ -59,7 +61,18 @@ export const Users: CollectionConfig = { }, }) - return usersQuery.docs[0] || null + return { + // Send the user back to authenticate, + // or send null if no user should be authenticated + user: usersQuery.docs[0] || null, + + // Optionally, you can return headers + // that you'd like Payload to set here when + // it returns the response + responseHeaders: new Headers({ + 'some-header': 'my header value' + }) + } } } ] diff --git a/packages/next/src/routes/graphql/handler.ts b/packages/next/src/routes/graphql/handler.ts index de1b0a86b5..02ba783d5d 100644 --- a/packages/next/src/routes/graphql/handler.ts +++ b/packages/next/src/routes/graphql/handler.ts @@ -9,6 +9,7 @@ import { addDataAndFileToRequest } from '../../utilities/addDataAndFileToRequest import { addLocalesToRequestFromData } from '../../utilities/addLocalesToRequest.js' import { createPayloadRequest } from '../../utilities/createPayloadRequest.js' import { headersWithCors } from '../../utilities/headersWithCors.js' +import { mergeHeaders } from '../../utilities/mergeHeaders.js' const handleError = async ( payload: Payload, @@ -122,7 +123,7 @@ export const POST = return response }, schema, - validationRules: (request, args, defaultRules) => defaultRules.concat(validationRules(args)), + validationRules: (_, args, defaultRules) => defaultRules.concat(validationRules(args)), })(originalRequest) const resHeaders = headersWithCors({ @@ -134,6 +135,10 @@ export const POST = resHeaders.append(key, headers[key]) } + if (basePayloadRequest.responseHeaders) { + mergeHeaders(basePayloadRequest.responseHeaders, resHeaders) + } + return new Response(apiResponse.body, { headers: resHeaders, status: apiResponse.status, diff --git a/packages/next/src/routes/rest/index.ts b/packages/next/src/routes/rest/index.ts index 047988ed3e..f0ca605e8a 100644 --- a/packages/next/src/routes/rest/index.ts +++ b/packages/next/src/routes/rest/index.ts @@ -21,6 +21,7 @@ import { addDataAndFileToRequest } from '../../utilities/addDataAndFileToRequest import { addLocalesToRequestFromData } from '../../utilities/addLocalesToRequest.js' import { createPayloadRequest } from '../../utilities/createPayloadRequest.js' import { headersWithCors } from '../../utilities/headersWithCors.js' +import { mergeHeaders } from '../../utilities/mergeHeaders.js' import { access } from './auth/access.js' import { forgotPassword } from './auth/forgotPassword.js' import { init } from './auth/init.js' @@ -122,7 +123,7 @@ const endpoints = { }, } -const handleCustomEndpoints = ({ +const handleCustomEndpoints = async ({ endpoints, entitySlug, payloadRequest, @@ -130,7 +131,7 @@ const handleCustomEndpoints = ({ endpoints: Endpoint[] | GlobalConfig['endpoints'] entitySlug?: string payloadRequest: PayloadRequest -}): Promise | Response => { +}): Promise => { if (endpoints && endpoints.length > 0) { let handlerParams = {} const { pathname } = payloadRequest @@ -170,7 +171,15 @@ const handleCustomEndpoints = ({ ...payloadRequest.routeParams, ...handlerParams, } - return customEndpoint.handler(payloadRequest) + const res = await customEndpoint.handler(payloadRequest) + + if (res instanceof Response) { + if (payloadRequest.responseHeaders) { + mergeHeaders(payloadRequest.responseHeaders, res.headers) + } + + return res + } } } @@ -376,13 +385,20 @@ export const GET = res = await endpoints.root.GET[slug1]({ req: payloadRequest }) } - if (res instanceof Response) return res + if (res instanceof Response) { + if (req.responseHeaders) { + mergeHeaders(req.responseHeaders, res.headers) + } + + return res + } // root routes const customEndpointResponse = await handleCustomEndpoints({ endpoints: req.payload.config.endpoints, payloadRequest: req, }) + if (customEndpointResponse) return customEndpointResponse return RouteNotFoundResponse({ @@ -545,13 +561,20 @@ export const POST = res = await endpoints.root.POST[slug1]({ req: payloadRequest }) } - if (res instanceof Response) return res + if (res instanceof Response) { + if (req.responseHeaders) { + mergeHeaders(req.responseHeaders, res.headers) + } + + return res + } // root routes const customEndpointResponse = await handleCustomEndpoints({ endpoints: req.payload.config.endpoints, payloadRequest: req, }) + if (customEndpointResponse) return customEndpointResponse return RouteNotFoundResponse({ @@ -626,13 +649,20 @@ export const DELETE = } } - if (res instanceof Response) return res + if (res instanceof Response) { + if (req.responseHeaders) { + mergeHeaders(req.responseHeaders, res.headers) + } + + return res + } // root routes const customEndpointResponse = await handleCustomEndpoints({ endpoints: req.payload.config.endpoints, payloadRequest: req, }) + if (customEndpointResponse) return customEndpointResponse return RouteNotFoundResponse({ @@ -708,13 +738,20 @@ export const PATCH = } } - if (res instanceof Response) return res + if (res instanceof Response) { + if (req.responseHeaders) { + mergeHeaders(req.responseHeaders, res.headers) + } + + return res + } // root routes const customEndpointResponse = await handleCustomEndpoints({ endpoints: req.payload.config.endpoints, payloadRequest: req, }) + if (customEndpointResponse) return customEndpointResponse return RouteNotFoundResponse({ diff --git a/packages/next/src/utilities/createPayloadRequest.ts b/packages/next/src/utilities/createPayloadRequest.ts index 7899783262..bc21523e8b 100644 --- a/packages/next/src/utilities/createPayloadRequest.ts +++ b/packages/next/src/utilities/createPayloadRequest.ts @@ -97,11 +97,15 @@ export const createPayloadRequest = async ({ req.payloadDataLoader = getDataLoader(req) - req.user = await executeAuthStrategies({ + const { responseHeaders, user } = await executeAuthStrategies({ headers: req.headers, isGraphQL, payload, }) + req.user = user + + if (responseHeaders) req.responseHeaders = responseHeaders + return req } diff --git a/packages/next/src/utilities/mergeHeaders.ts b/packages/next/src/utilities/mergeHeaders.ts new file mode 100644 index 0000000000..6fdbe352bb --- /dev/null +++ b/packages/next/src/utilities/mergeHeaders.ts @@ -0,0 +1,33 @@ +const headersToJoin = ['set-cookie', 'warning', 'www-authenticate', 'proxy-authenticate', 'vary'] + +export function mergeHeaders(sourceHeaders: Headers, destinationHeaders: Headers): void { + // Create a map to store combined headers + const combinedHeaders = new Headers() + + // Add existing destination headers to the combined map + destinationHeaders.forEach((value, key) => { + combinedHeaders.set(key, value) + }) + + // Add source headers to the combined map, joining specific headers + sourceHeaders.forEach((value, key) => { + const lowerKey = key.toLowerCase() + if (headersToJoin.includes(lowerKey)) { + if (combinedHeaders.has(key)) { + combinedHeaders.set(key, `${combinedHeaders.get(key)}, ${value}`) + } else { + combinedHeaders.set(key, value) + } + } else { + combinedHeaders.set(key, value) + } + }) + + // Clear the destination headers and set the combined headers + destinationHeaders.forEach((_, key) => { + destinationHeaders.delete(key) + }) + combinedHeaders.forEach((value, key) => { + destinationHeaders.append(key, value) + }) +} diff --git a/packages/payload/src/auth/executeAuthStrategies.ts b/packages/payload/src/auth/executeAuthStrategies.ts index 8fba1be338..d763107557 100644 --- a/packages/payload/src/auth/executeAuthStrategies.ts +++ b/packages/payload/src/auth/executeAuthStrategies.ts @@ -1,14 +1,16 @@ -import type { TypedUser } from '../index.js' -import type { AuthStrategyFunctionArgs } from './index.js' +import type { AuthStrategyFunctionArgs, AuthStrategyResult } from './index.js' export const executeAuthStrategies = async ( args: AuthStrategyFunctionArgs, -): Promise => { - return args.payload.authStrategies.reduce(async (accumulatorPromise, strategy) => { - const authUser = await accumulatorPromise - if (!authUser) { - return strategy.authenticate(args) - } - return authUser - }, Promise.resolve(null)) +): Promise => { + return args.payload.authStrategies.reduce( + async (accumulatorPromise, strategy) => { + const result: AuthStrategyResult = await accumulatorPromise + if (!result.user) { + return strategy.authenticate(args) + } + return result + }, + Promise.resolve({ user: null }), + ) } diff --git a/packages/payload/src/auth/operations/auth.ts b/packages/payload/src/auth/operations/auth.ts index 071baedac6..ae9236b803 100644 --- a/packages/payload/src/auth/operations/auth.ts +++ b/packages/payload/src/auth/operations/auth.ts @@ -15,6 +15,7 @@ export type AuthArgs = { export type AuthResult = { permissions: Permissions + responseHeaders?: Headers user: TypedUser | null } @@ -26,12 +27,13 @@ export const auth = async (args: Required): Promise => { try { const shouldCommit = await initTransaction(req) - const user = await executeAuthStrategies({ + const { responseHeaders, user } = await executeAuthStrategies({ headers, payload, }) req.user = user + req.responseHeaders = responseHeaders const permissions = await getAccessResults({ req, @@ -41,6 +43,7 @@ export const auth = async (args: Required): Promise => { return { permissions, + responseHeaders, user, } } catch (error: unknown) { diff --git a/packages/payload/src/auth/strategies/apiKey.ts b/packages/payload/src/auth/strategies/apiKey.ts index 2094284bb5..6454c76ef2 100644 --- a/packages/payload/src/auth/strategies/apiKey.ts +++ b/packages/payload/src/auth/strategies/apiKey.ts @@ -48,12 +48,14 @@ export const APIKeyAuthentication = user.collection = collectionConfig.slug user._strategy = 'api-key' - return user as User + return { + user: user as User, + } } } catch (err) { - return null + return { user: null } } } - return null + return { user: null } } diff --git a/packages/payload/src/auth/strategies/jwt.ts b/packages/payload/src/auth/strategies/jwt.ts index 6de2f69af9..1b3ec2783b 100644 --- a/packages/payload/src/auth/strategies/jwt.ts +++ b/packages/payload/src/auth/strategies/jwt.ts @@ -29,11 +29,13 @@ export const JWTAuthentication: AuthStrategyFunction = async ({ if (user && (!collection.config.auth.verify || user._verified)) { user.collection = collection.config.slug user._strategy = 'local-jwt' - return user as User + return { + user: user as User, + } } else { - return null + return { user: null } } } catch (error) { - return null + return { user: null } } } diff --git a/packages/payload/src/auth/types.ts b/packages/payload/src/auth/types.ts index facf7e474b..3452d808f9 100644 --- a/packages/payload/src/auth/types.ts +++ b/packages/payload/src/auth/types.ts @@ -101,9 +101,15 @@ export type AuthStrategyFunctionArgs = { isGraphQL?: boolean payload: Payload } + +export type AuthStrategyResult = { + responseHeaders?: Headers + user: User | null +} + export type AuthStrategyFunction = ( args: AuthStrategyFunctionArgs, -) => Promise | User | null +) => AuthStrategyResult | Promise export type AuthStrategy = { authenticate: AuthStrategyFunction name: string diff --git a/packages/payload/src/types/index.ts b/packages/payload/src/types/index.ts index 47e40a636c..bcca8c1ca2 100644 --- a/packages/payload/src/types/index.ts +++ b/packages/payload/src/types/index.ts @@ -31,6 +31,8 @@ export type CustomPayloadRequestProperties = { payloadUploadSizes?: Record /** Query params on the request */ query: Record + /** Any response headers that are required to be set when a response is sent */ + responseHeaders?: Headers /** The route parameters * @example * /:collection/:id -> /posts/123 diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c738d952cc..5e2569df85 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -633,7 +633,7 @@ importers: version: 6.11.0(webpack@5.91.0) css-minimizer-webpack-plugin: specifier: ^6.0.0 - version: 6.0.0(esbuild@0.19.12)(webpack@5.91.0) + version: 6.0.0(webpack@5.91.0) mini-css-extract-plugin: specifier: 1.6.2 version: 1.6.2(webpack@5.91.0) @@ -642,7 +642,7 @@ importers: version: link:../payload postcss-loader: specifier: ^8.1.1 - version: 8.1.1(postcss@8.4.38)(typescript@5.5.2)(webpack@5.91.0) + version: 8.1.1(postcss@8.4.38)(webpack@5.91.0) postcss-preset-env: specifier: ^9.5.14 version: 9.5.14(postcss@8.4.38) @@ -657,10 +657,10 @@ importers: version: 1.12.1 terser-webpack-plugin: specifier: ^5.3.10 - version: 5.3.10(@swc/core@1.6.5)(esbuild@0.19.12)(webpack@5.91.0) + version: 5.3.10(@swc/core@1.6.5)(webpack@5.91.0) webpack: specifier: ^5.78.0 - version: 5.91.0(@swc/core@1.6.5)(esbuild@0.19.12)(webpack-cli@5.1.4) + version: 5.91.0(@swc/core@1.6.5)(webpack-cli@5.1.4) webpack-cli: specifier: ^5.1.4 version: 5.1.4(webpack@5.91.0) @@ -7859,7 +7859,7 @@ packages: webpack: 5.x.x webpack-cli: 5.x.x dependencies: - webpack: 5.91.0(@swc/core@1.6.5)(esbuild@0.19.12)(webpack-cli@5.1.4) + webpack: 5.91.0(@swc/core@1.6.5)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack@5.91.0) dev: true @@ -7870,7 +7870,7 @@ packages: webpack: 5.x.x webpack-cli: 5.x.x dependencies: - webpack: 5.91.0(@swc/core@1.6.5)(esbuild@0.19.12)(webpack-cli@5.1.4) + webpack: 5.91.0(@swc/core@1.6.5)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack@5.91.0) dev: true @@ -7885,7 +7885,7 @@ packages: webpack-dev-server: optional: true dependencies: - webpack: 5.91.0(@swc/core@1.6.5)(esbuild@0.19.12)(webpack-cli@5.1.4) + webpack: 5.91.0(@swc/core@1.6.5)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack@5.91.0) dev: true @@ -9140,6 +9140,21 @@ packages: yaml: 1.10.2 dev: false + /cosmiconfig@9.0.0: + resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} + engines: {node: '>=14'} + peerDependencies: + typescript: 5.5.2 + peerDependenciesMeta: + typescript: + optional: true + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + dev: true + /cosmiconfig@9.0.0(typescript@5.5.2): resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} engines: {node: '>=14'} @@ -9261,10 +9276,10 @@ packages: postcss-modules-values: 4.0.0(postcss@8.4.38) postcss-value-parser: 4.2.0 semver: 7.6.0 - webpack: 5.91.0(@swc/core@1.6.5)(esbuild@0.19.12)(webpack-cli@5.1.4) + webpack: 5.91.0(@swc/core@1.6.5)(webpack-cli@5.1.4) dev: true - /css-minimizer-webpack-plugin@6.0.0(esbuild@0.19.12)(webpack@5.91.0): + /css-minimizer-webpack-plugin@6.0.0(webpack@5.91.0): resolution: {integrity: sha512-BLpR9CCDkKvhO3i0oZQgad6v9pCxUuhSc5RT6iUEy9M8hBXi4TJb5vqF2GQ2deqYHmRi3O6IR9hgAZQWg0EBwA==} engines: {node: '>= 18.12.0'} peerDependencies: @@ -9291,12 +9306,11 @@ packages: dependencies: '@jridgewell/trace-mapping': 0.3.25 cssnano: 6.1.2(postcss@8.4.38) - esbuild: 0.19.12 jest-worker: 29.7.0 postcss: 8.4.38 schema-utils: 4.2.0 serialize-javascript: 6.0.2 - webpack: 5.91.0(@swc/core@1.6.5)(esbuild@0.19.12)(webpack-cli@5.1.4) + webpack: 5.91.0(@swc/core@1.6.5)(webpack-cli@5.1.4) dev: true /css-prefers-color-scheme@9.0.1(postcss@8.4.38): @@ -13344,7 +13358,7 @@ packages: dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.91.0(@swc/core@1.6.5)(esbuild@0.19.12)(webpack-cli@5.1.4) + webpack: 5.91.0(@swc/core@1.6.5)(webpack-cli@5.1.4) webpack-sources: 1.4.3 dev: true @@ -14682,6 +14696,28 @@ packages: - typescript dev: true + /postcss-loader@8.1.1(postcss@8.4.38)(webpack@5.91.0): + resolution: {integrity: sha512-0IeqyAsG6tYiDRCYKQJLAmgQr47DX6N7sFSWvQxt6AcupX8DIdmykuk/o/tx0Lze3ErGHJEp5OSRxrelC6+NdQ==} + engines: {node: '>= 18.12.0'} + peerDependencies: + '@rspack/core': 0.x || 1.x + postcss: ^7.0.0 || ^8.0.1 + webpack: ^5.0.0 + peerDependenciesMeta: + '@rspack/core': + optional: true + webpack: + optional: true + dependencies: + cosmiconfig: 9.0.0 + jiti: 1.21.0 + postcss: 8.4.38 + semver: 7.6.0 + webpack: 5.91.0(@swc/core@1.6.5)(webpack-cli@5.1.4) + transitivePeerDependencies: + - typescript + dev: true + /postcss-logical@7.0.1(postcss@8.4.38): resolution: {integrity: sha512-8GwUQZE0ri0K0HJHkDv87XOLC8DE0msc+HoWLeKdtjDZEwpZ5xuK3QdV6FhmHSQW40LPkg43QzvATRAI3LsRkg==} engines: {node: ^14 || ^16 || >=18} @@ -16093,7 +16129,7 @@ packages: dependencies: neo-async: 2.6.2 sass: 1.77.4 - webpack: 5.91.0(@swc/core@1.6.5)(esbuild@0.19.12)(webpack-cli@5.1.4) + webpack: 5.91.0(@swc/core@1.6.5)(webpack-cli@5.1.4) dev: true /sass@1.77.4: @@ -16880,7 +16916,7 @@ packages: dependencies: '@swc/core': 1.6.5 '@swc/counter': 0.1.3 - webpack: 5.91.0(@swc/core@1.6.5)(esbuild@0.19.12)(webpack-cli@5.1.4) + webpack: 5.91.0(@swc/core@1.6.5)(webpack-cli@5.1.4) dev: true /swc-plugin-transform-remove-imports@1.12.1: @@ -17042,6 +17078,31 @@ packages: webpack: 5.91.0(@swc/core@1.6.5)(esbuild@0.21.5) dev: true + /terser-webpack-plugin@5.3.10(@swc/core@1.6.5)(webpack@5.91.0): + resolution: {integrity: sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==} + engines: {node: '>= 10.13.0'} + peerDependencies: + '@swc/core': '*' + esbuild: '*' + uglify-js: '*' + webpack: ^5.1.0 + peerDependenciesMeta: + '@swc/core': + optional: true + esbuild: + optional: true + uglify-js: + optional: true + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + '@swc/core': 1.6.5 + jest-worker: 27.5.1 + schema-utils: 3.3.0 + serialize-javascript: 6.0.2 + terser: 5.30.3 + webpack: 5.91.0(@swc/core@1.6.5)(webpack-cli@5.1.4) + dev: true + /terser@5.30.3: resolution: {integrity: sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA==} engines: {node: '>=10'} @@ -17797,7 +17858,7 @@ packages: import-local: 3.1.0 interpret: 3.1.1 rechoir: 0.8.0 - webpack: 5.91.0(@swc/core@1.6.5)(esbuild@0.19.12)(webpack-cli@5.1.4) + webpack: 5.91.0(@swc/core@1.6.5)(webpack-cli@5.1.4) webpack-merge: 5.10.0 dev: true @@ -17903,6 +17964,47 @@ packages: - uglify-js dev: true + /webpack@5.91.0(@swc/core@1.6.5)(webpack-cli@5.1.4): + resolution: {integrity: sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + dependencies: + '@types/eslint-scope': 3.7.7 + '@types/estree': 1.0.5 + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/wasm-edit': 1.12.1 + '@webassemblyjs/wasm-parser': 1.12.1 + acorn: 8.11.3 + acorn-import-assertions: 1.9.0(acorn@8.11.3) + browserslist: 4.23.0 + chrome-trace-event: 1.0.3 + enhanced-resolve: 5.16.0 + es-module-lexer: 1.5.0 + eslint-scope: 5.1.1 + events: 3.3.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + json-parse-even-better-errors: 2.3.1 + loader-runner: 4.3.0 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 3.3.0 + tapable: 2.2.1 + terser-webpack-plugin: 5.3.10(@swc/core@1.6.5)(webpack@5.91.0) + watchpack: 2.4.1 + webpack-cli: 5.1.4(webpack@5.91.0) + webpack-sources: 3.2.3 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + dev: true + /whatwg-encoding@2.0.0: resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} engines: {node: '>=12'} diff --git a/test/auth/custom-strategy/config.ts b/test/auth/custom-strategy/config.ts index b8e6b64e02..87c58fc5a1 100644 --- a/test/auth/custom-strategy/config.ts +++ b/test/auth/custom-strategy/config.ts @@ -25,12 +25,17 @@ const customAuthenticationStrategy: AuthStrategyFunction = async ({ headers, pay }) const user = usersQuery.docs[0] || null - if (!user) return null + if (!user) return { user: null } return { - ...user, - _strategy: `${usersSlug}-${strategyName}`, - collection: usersSlug, + user: { + ...user, + _strategy: `${usersSlug}-${strategyName}`, + collection: usersSlug, + }, + responseHeaders: new Headers({ + 'Smile-For-Me': 'please', + }), } } diff --git a/test/auth/custom-strategy/int.spec.ts b/test/auth/custom-strategy/int.spec.ts index 2ce5d8ff0c..329b2d64c1 100644 --- a/test/auth/custom-strategy/int.spec.ts +++ b/test/auth/custom-strategy/int.spec.ts @@ -48,6 +48,8 @@ describe('AuthStrategies', () => { const data = await response.json() + // Expect that the auth strategy should be able to return headers + expect(response.headers.has('Smile-For-Me')).toBeTruthy() expect(response.status).toBe(200) expect(data.user.name).toBe(name) })