feat(next)!: allows auth strategies to return headers that need to be… (#6964)

## Description

Some authentication strategies may need to set headers for responses,
such as updating cookies via a refresh token, and similar. This PR
extends Payload's auth strategy capabilities with a manner of
accomplishing this.

This is a breaking change if you have custom authentication strategies
in Payload's 3.0 beta. But it's a simple one to update.

Instead of your custom auth strategy returning the `user`, now you must
return an object with a `user` property.

This is because you can now also optionally return `responseHeaders`,
which will be returned by Payload API responses if you define them in
your auth strategies. This can be helpful for cases where you need to
set cookies and similar, directly within your auth strategies.

Before: 

```ts
return user
```

After:

```ts
return { user }
```
This commit is contained in:
James Mikrut
2024-06-27 17:33:25 -04:00
committed by GitHub
parent 07f3f273cd
commit 37e2da012b
14 changed files with 267 additions and 49 deletions

View File

@@ -33,10 +33,12 @@ The `authenticate` function is passed the following arguments:
### Example Strategy ### 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 ```ts
import { CollectionConfig } from 'payload/types' import { CollectionConfig } from 'payload'
export const Users: CollectionConfig = { export const Users: CollectionConfig = {
slug: 'users', 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'
})
}
} }
} }
] ]

View File

@@ -9,6 +9,7 @@ import { addDataAndFileToRequest } from '../../utilities/addDataAndFileToRequest
import { addLocalesToRequestFromData } from '../../utilities/addLocalesToRequest.js' import { addLocalesToRequestFromData } from '../../utilities/addLocalesToRequest.js'
import { createPayloadRequest } from '../../utilities/createPayloadRequest.js' import { createPayloadRequest } from '../../utilities/createPayloadRequest.js'
import { headersWithCors } from '../../utilities/headersWithCors.js' import { headersWithCors } from '../../utilities/headersWithCors.js'
import { mergeHeaders } from '../../utilities/mergeHeaders.js'
const handleError = async ( const handleError = async (
payload: Payload, payload: Payload,
@@ -122,7 +123,7 @@ export const POST =
return response return response
}, },
schema, schema,
validationRules: (request, args, defaultRules) => defaultRules.concat(validationRules(args)), validationRules: (_, args, defaultRules) => defaultRules.concat(validationRules(args)),
})(originalRequest) })(originalRequest)
const resHeaders = headersWithCors({ const resHeaders = headersWithCors({
@@ -134,6 +135,10 @@ export const POST =
resHeaders.append(key, headers[key]) resHeaders.append(key, headers[key])
} }
if (basePayloadRequest.responseHeaders) {
mergeHeaders(basePayloadRequest.responseHeaders, resHeaders)
}
return new Response(apiResponse.body, { return new Response(apiResponse.body, {
headers: resHeaders, headers: resHeaders,
status: apiResponse.status, status: apiResponse.status,

View File

@@ -21,6 +21,7 @@ import { addDataAndFileToRequest } from '../../utilities/addDataAndFileToRequest
import { addLocalesToRequestFromData } from '../../utilities/addLocalesToRequest.js' import { addLocalesToRequestFromData } from '../../utilities/addLocalesToRequest.js'
import { createPayloadRequest } from '../../utilities/createPayloadRequest.js' import { createPayloadRequest } from '../../utilities/createPayloadRequest.js'
import { headersWithCors } from '../../utilities/headersWithCors.js' import { headersWithCors } from '../../utilities/headersWithCors.js'
import { mergeHeaders } from '../../utilities/mergeHeaders.js'
import { access } from './auth/access.js' import { access } from './auth/access.js'
import { forgotPassword } from './auth/forgotPassword.js' import { forgotPassword } from './auth/forgotPassword.js'
import { init } from './auth/init.js' import { init } from './auth/init.js'
@@ -122,7 +123,7 @@ const endpoints = {
}, },
} }
const handleCustomEndpoints = ({ const handleCustomEndpoints = async ({
endpoints, endpoints,
entitySlug, entitySlug,
payloadRequest, payloadRequest,
@@ -130,7 +131,7 @@ const handleCustomEndpoints = ({
endpoints: Endpoint[] | GlobalConfig['endpoints'] endpoints: Endpoint[] | GlobalConfig['endpoints']
entitySlug?: string entitySlug?: string
payloadRequest: PayloadRequest payloadRequest: PayloadRequest
}): Promise<Response> | Response => { }): Promise<Response> => {
if (endpoints && endpoints.length > 0) { if (endpoints && endpoints.length > 0) {
let handlerParams = {} let handlerParams = {}
const { pathname } = payloadRequest const { pathname } = payloadRequest
@@ -170,7 +171,15 @@ const handleCustomEndpoints = ({
...payloadRequest.routeParams, ...payloadRequest.routeParams,
...handlerParams, ...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 }) 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 // root routes
const customEndpointResponse = await handleCustomEndpoints({ const customEndpointResponse = await handleCustomEndpoints({
endpoints: req.payload.config.endpoints, endpoints: req.payload.config.endpoints,
payloadRequest: req, payloadRequest: req,
}) })
if (customEndpointResponse) return customEndpointResponse if (customEndpointResponse) return customEndpointResponse
return RouteNotFoundResponse({ return RouteNotFoundResponse({
@@ -545,13 +561,20 @@ export const POST =
res = await endpoints.root.POST[slug1]({ req: payloadRequest }) 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 // root routes
const customEndpointResponse = await handleCustomEndpoints({ const customEndpointResponse = await handleCustomEndpoints({
endpoints: req.payload.config.endpoints, endpoints: req.payload.config.endpoints,
payloadRequest: req, payloadRequest: req,
}) })
if (customEndpointResponse) return customEndpointResponse if (customEndpointResponse) return customEndpointResponse
return RouteNotFoundResponse({ 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 // root routes
const customEndpointResponse = await handleCustomEndpoints({ const customEndpointResponse = await handleCustomEndpoints({
endpoints: req.payload.config.endpoints, endpoints: req.payload.config.endpoints,
payloadRequest: req, payloadRequest: req,
}) })
if (customEndpointResponse) return customEndpointResponse if (customEndpointResponse) return customEndpointResponse
return RouteNotFoundResponse({ 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 // root routes
const customEndpointResponse = await handleCustomEndpoints({ const customEndpointResponse = await handleCustomEndpoints({
endpoints: req.payload.config.endpoints, endpoints: req.payload.config.endpoints,
payloadRequest: req, payloadRequest: req,
}) })
if (customEndpointResponse) return customEndpointResponse if (customEndpointResponse) return customEndpointResponse
return RouteNotFoundResponse({ return RouteNotFoundResponse({

View File

@@ -97,11 +97,15 @@ export const createPayloadRequest = async ({
req.payloadDataLoader = getDataLoader(req) req.payloadDataLoader = getDataLoader(req)
req.user = await executeAuthStrategies({ const { responseHeaders, user } = await executeAuthStrategies({
headers: req.headers, headers: req.headers,
isGraphQL, isGraphQL,
payload, payload,
}) })
req.user = user
if (responseHeaders) req.responseHeaders = responseHeaders
return req return req
} }

View File

@@ -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)
})
}

View File

@@ -1,14 +1,16 @@
import type { TypedUser } from '../index.js' import type { AuthStrategyFunctionArgs, AuthStrategyResult } from './index.js'
import type { AuthStrategyFunctionArgs } from './index.js'
export const executeAuthStrategies = async ( export const executeAuthStrategies = async (
args: AuthStrategyFunctionArgs, args: AuthStrategyFunctionArgs,
): Promise<TypedUser | null> => { ): Promise<AuthStrategyResult> => {
return args.payload.authStrategies.reduce(async (accumulatorPromise, strategy) => { return args.payload.authStrategies.reduce(
const authUser = await accumulatorPromise async (accumulatorPromise, strategy) => {
if (!authUser) { const result: AuthStrategyResult = await accumulatorPromise
return strategy.authenticate(args) if (!result.user) {
} return strategy.authenticate(args)
return authUser }
}, Promise.resolve(null)) return result
},
Promise.resolve({ user: null }),
)
} }

View File

@@ -15,6 +15,7 @@ export type AuthArgs = {
export type AuthResult = { export type AuthResult = {
permissions: Permissions permissions: Permissions
responseHeaders?: Headers
user: TypedUser | null user: TypedUser | null
} }
@@ -26,12 +27,13 @@ export const auth = async (args: Required<AuthArgs>): Promise<AuthResult> => {
try { try {
const shouldCommit = await initTransaction(req) const shouldCommit = await initTransaction(req)
const user = await executeAuthStrategies({ const { responseHeaders, user } = await executeAuthStrategies({
headers, headers,
payload, payload,
}) })
req.user = user req.user = user
req.responseHeaders = responseHeaders
const permissions = await getAccessResults({ const permissions = await getAccessResults({
req, req,
@@ -41,6 +43,7 @@ export const auth = async (args: Required<AuthArgs>): Promise<AuthResult> => {
return { return {
permissions, permissions,
responseHeaders,
user, user,
} }
} catch (error: unknown) { } catch (error: unknown) {

View File

@@ -48,12 +48,14 @@ export const APIKeyAuthentication =
user.collection = collectionConfig.slug user.collection = collectionConfig.slug
user._strategy = 'api-key' user._strategy = 'api-key'
return user as User return {
user: user as User,
}
} }
} catch (err) { } catch (err) {
return null return { user: null }
} }
} }
return null return { user: null }
} }

View File

@@ -29,11 +29,13 @@ export const JWTAuthentication: AuthStrategyFunction = async ({
if (user && (!collection.config.auth.verify || user._verified)) { if (user && (!collection.config.auth.verify || user._verified)) {
user.collection = collection.config.slug user.collection = collection.config.slug
user._strategy = 'local-jwt' user._strategy = 'local-jwt'
return user as User return {
user: user as User,
}
} else { } else {
return null return { user: null }
} }
} catch (error) { } catch (error) {
return null return { user: null }
} }
} }

View File

@@ -101,9 +101,15 @@ export type AuthStrategyFunctionArgs = {
isGraphQL?: boolean isGraphQL?: boolean
payload: Payload payload: Payload
} }
export type AuthStrategyResult = {
responseHeaders?: Headers
user: User | null
}
export type AuthStrategyFunction = ( export type AuthStrategyFunction = (
args: AuthStrategyFunctionArgs, args: AuthStrategyFunctionArgs,
) => Promise<User | null> | User | null ) => AuthStrategyResult | Promise<AuthStrategyResult>
export type AuthStrategy = { export type AuthStrategy = {
authenticate: AuthStrategyFunction authenticate: AuthStrategyFunction
name: string name: string

View File

@@ -31,6 +31,8 @@ export type CustomPayloadRequestProperties = {
payloadUploadSizes?: Record<string, Buffer> payloadUploadSizes?: Record<string, Buffer>
/** Query params on the request */ /** Query params on the request */
query: Record<string, unknown> query: Record<string, unknown>
/** Any response headers that are required to be set when a response is sent */
responseHeaders?: Headers
/** The route parameters /** The route parameters
* @example * @example
* /:collection/:id -> /posts/123 * /:collection/:id -> /posts/123

132
pnpm-lock.yaml generated
View File

@@ -633,7 +633,7 @@ importers:
version: 6.11.0(webpack@5.91.0) version: 6.11.0(webpack@5.91.0)
css-minimizer-webpack-plugin: css-minimizer-webpack-plugin:
specifier: ^6.0.0 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: mini-css-extract-plugin:
specifier: 1.6.2 specifier: 1.6.2
version: 1.6.2(webpack@5.91.0) version: 1.6.2(webpack@5.91.0)
@@ -642,7 +642,7 @@ importers:
version: link:../payload version: link:../payload
postcss-loader: postcss-loader:
specifier: ^8.1.1 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: postcss-preset-env:
specifier: ^9.5.14 specifier: ^9.5.14
version: 9.5.14(postcss@8.4.38) version: 9.5.14(postcss@8.4.38)
@@ -657,10 +657,10 @@ importers:
version: 1.12.1 version: 1.12.1
terser-webpack-plugin: terser-webpack-plugin:
specifier: ^5.3.10 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: webpack:
specifier: ^5.78.0 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: webpack-cli:
specifier: ^5.1.4 specifier: ^5.1.4
version: 5.1.4(webpack@5.91.0) version: 5.1.4(webpack@5.91.0)
@@ -7859,7 +7859,7 @@ packages:
webpack: 5.x.x webpack: 5.x.x
webpack-cli: 5.x.x webpack-cli: 5.x.x
dependencies: 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) webpack-cli: 5.1.4(webpack@5.91.0)
dev: true dev: true
@@ -7870,7 +7870,7 @@ packages:
webpack: 5.x.x webpack: 5.x.x
webpack-cli: 5.x.x webpack-cli: 5.x.x
dependencies: 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) webpack-cli: 5.1.4(webpack@5.91.0)
dev: true dev: true
@@ -7885,7 +7885,7 @@ packages:
webpack-dev-server: webpack-dev-server:
optional: true optional: true
dependencies: 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) webpack-cli: 5.1.4(webpack@5.91.0)
dev: true dev: true
@@ -9140,6 +9140,21 @@ packages:
yaml: 1.10.2 yaml: 1.10.2
dev: false 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): /cosmiconfig@9.0.0(typescript@5.5.2):
resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==}
engines: {node: '>=14'} engines: {node: '>=14'}
@@ -9261,10 +9276,10 @@ packages:
postcss-modules-values: 4.0.0(postcss@8.4.38) postcss-modules-values: 4.0.0(postcss@8.4.38)
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
semver: 7.6.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 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==} resolution: {integrity: sha512-BLpR9CCDkKvhO3i0oZQgad6v9pCxUuhSc5RT6iUEy9M8hBXi4TJb5vqF2GQ2deqYHmRi3O6IR9hgAZQWg0EBwA==}
engines: {node: '>= 18.12.0'} engines: {node: '>= 18.12.0'}
peerDependencies: peerDependencies:
@@ -9291,12 +9306,11 @@ packages:
dependencies: dependencies:
'@jridgewell/trace-mapping': 0.3.25 '@jridgewell/trace-mapping': 0.3.25
cssnano: 6.1.2(postcss@8.4.38) cssnano: 6.1.2(postcss@8.4.38)
esbuild: 0.19.12
jest-worker: 29.7.0 jest-worker: 29.7.0
postcss: 8.4.38 postcss: 8.4.38
schema-utils: 4.2.0 schema-utils: 4.2.0
serialize-javascript: 6.0.2 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 dev: true
/css-prefers-color-scheme@9.0.1(postcss@8.4.38): /css-prefers-color-scheme@9.0.1(postcss@8.4.38):
@@ -13344,7 +13358,7 @@ packages:
dependencies: dependencies:
loader-utils: 2.0.4 loader-utils: 2.0.4
schema-utils: 3.3.0 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 webpack-sources: 1.4.3
dev: true dev: true
@@ -14682,6 +14696,28 @@ packages:
- typescript - typescript
dev: true 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): /postcss-logical@7.0.1(postcss@8.4.38):
resolution: {integrity: sha512-8GwUQZE0ri0K0HJHkDv87XOLC8DE0msc+HoWLeKdtjDZEwpZ5xuK3QdV6FhmHSQW40LPkg43QzvATRAI3LsRkg==} resolution: {integrity: sha512-8GwUQZE0ri0K0HJHkDv87XOLC8DE0msc+HoWLeKdtjDZEwpZ5xuK3QdV6FhmHSQW40LPkg43QzvATRAI3LsRkg==}
engines: {node: ^14 || ^16 || >=18} engines: {node: ^14 || ^16 || >=18}
@@ -16093,7 +16129,7 @@ packages:
dependencies: dependencies:
neo-async: 2.6.2 neo-async: 2.6.2
sass: 1.77.4 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 dev: true
/sass@1.77.4: /sass@1.77.4:
@@ -16880,7 +16916,7 @@ packages:
dependencies: dependencies:
'@swc/core': 1.6.5 '@swc/core': 1.6.5
'@swc/counter': 0.1.3 '@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 dev: true
/swc-plugin-transform-remove-imports@1.12.1: /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) webpack: 5.91.0(@swc/core@1.6.5)(esbuild@0.21.5)
dev: true 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: /terser@5.30.3:
resolution: {integrity: sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA==} resolution: {integrity: sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA==}
engines: {node: '>=10'} engines: {node: '>=10'}
@@ -17797,7 +17858,7 @@ packages:
import-local: 3.1.0 import-local: 3.1.0
interpret: 3.1.1 interpret: 3.1.1
rechoir: 0.8.0 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 webpack-merge: 5.10.0
dev: true dev: true
@@ -17903,6 +17964,47 @@ packages:
- uglify-js - uglify-js
dev: true 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: /whatwg-encoding@2.0.0:
resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==}
engines: {node: '>=12'} engines: {node: '>=12'}

View File

@@ -25,12 +25,17 @@ const customAuthenticationStrategy: AuthStrategyFunction = async ({ headers, pay
}) })
const user = usersQuery.docs[0] || null const user = usersQuery.docs[0] || null
if (!user) return null if (!user) return { user: null }
return { return {
...user, user: {
_strategy: `${usersSlug}-${strategyName}`, ...user,
collection: usersSlug, _strategy: `${usersSlug}-${strategyName}`,
collection: usersSlug,
},
responseHeaders: new Headers({
'Smile-For-Me': 'please',
}),
} }
} }

View File

@@ -48,6 +48,8 @@ describe('AuthStrategies', () => {
const data = await response.json() 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(response.status).toBe(200)
expect(data.user.name).toBe(name) expect(data.user.name).toBe(name)
}) })