Skip to content

Commit ca6f849

Browse files
authored
feat: adds new canSetHeaders prop to auth strategies (#12591)
Exposes a new argument to authentication strategies which allows the author to determine if this auth strategy has the capability of setting response headers or not. This is useful because some auth strategies may want to set headers, but in Next.js server components (AKA the admin panel), it's not possible to set headers. It is, however, possible to set headers within API responses and similar contexts. So, an author might decide to only run operations that require setting headers (i.e. refreshing an access token) if the auth strategy is being executed in contexts where setting headers is possible.
1 parent 7e873a9 commit ca6f849

File tree

10 files changed

+28
-8
lines changed

10 files changed

+28
-8
lines changed

docs/authentication/custom-strategies.mdx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,12 @@ A strategy is made up of the following:
2525

2626
The `authenticate` function is passed the following arguments:
2727

28-
| Argument | Description |
29-
| ---------------- | ------------------------------------------------------------------------------------------------- |
30-
| **`headers`** \* | The headers on the incoming request. Useful for retrieving identifiable information on a request. |
31-
| **`payload`** \* | The Payload class. Useful for authenticating the identifiable information against Payload. |
32-
| **`isGraphQL`** | Whether or not the request was made from a GraphQL endpoint. Default is `false`. |
28+
| Argument | Description |
29+
| ---------------------- | ------------------------------------------------------------------------------------------------------------------- |
30+
| **`canSetHeaders`** \* | Whether or not the strategy is being executed from a context where response headers can be set. Default is `false`. |
31+
| **`headers`** \* | The headers on the incoming request. Useful for retrieving identifiable information on a request. |
32+
| **`payload`** \* | The Payload class. Useful for authenticating the identifiable information against Payload. |
33+
| **`isGraphQL`** | Whether or not the strategy is being executed within the GraphQL endpoint. Default is `false`. |
3334

3435
### Example Strategy
3536

docs/local-api/overview.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ available:
329329
// responseHeaders: { ... } // returned headers from the response
330330
// }
331331

332-
const result = await payload.auth({ headers })
332+
const result = await payload.auth({ headers, canSetHeaders: false })
333333
```
334334

335335
### Login

packages/next/src/routes/graphql/handler.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ export const POST =
9999
(config: Promise<SanitizedConfig> | SanitizedConfig) => async (request: Request) => {
100100
const originalRequest = request.clone()
101101
const req = await createPayloadRequest({
102+
canSetHeaders: true,
102103
config,
103104
request,
104105
})

packages/next/src/utilities/initReq.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,13 @@ const reqCache = selectiveCache<Result>('req')
4949
* As access control and getting the request locale is dependent on the current URL and
5050
*/
5151
export const initReq = async function ({
52+
canSetHeaders,
5253
configPromise,
5354
importMap,
5455
key,
5556
overrides,
5657
}: {
58+
canSetHeaders?: boolean
5759
configPromise: Promise<SanitizedConfig> | SanitizedConfig
5860
importMap: ImportMap
5961
key: string
@@ -77,6 +79,7 @@ export const initReq = async function ({
7779
})
7880

7981
const { responseHeaders, user } = await executeAuthStrategies({
82+
canSetHeaders,
8083
headers,
8184
payload,
8285
})

packages/payload/src/auth/executeAuthStrategies.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ export const executeAuthStrategies = async (
1414
for (const strategy of args.payload.authStrategies) {
1515
// add the configured AuthStrategy `name` to the strategy function args
1616
args.strategyName = strategy.name
17+
args.isGraphQL = Boolean(args.isGraphQL)
18+
args.canSetHeaders = Boolean(args.canSetHeaders)
1719

1820
try {
1921
const authResult = await strategy.authenticate(args)

packages/payload/src/auth/operations/auth.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ import { executeAuthStrategies } from '../executeAuthStrategies.js'
66
import { getAccessResults } from '../getAccessResults.js'
77

88
export type AuthArgs = {
9+
/**
10+
* Specify if it's possible for auth strategies to set headers within this operation.
11+
*/
12+
canSetHeaders?: boolean
913
headers: Request['headers']
1014
req?: Omit<PayloadRequest, 'user'>
1115
}
@@ -17,12 +21,13 @@ export type AuthResult = {
1721
}
1822

1923
export const auth = async (args: Required<AuthArgs>): Promise<AuthResult> => {
20-
const { headers } = args
24+
const { canSetHeaders, headers } = args
2125
const req = args.req as PayloadRequest
2226
const { payload } = req
2327

2428
try {
2529
const { responseHeaders, user } = await executeAuthStrategies({
30+
canSetHeaders,
2631
headers,
2732
payload,
2833
})

packages/payload/src/auth/operations/local/auth.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export const auth = async (payload: Payload, options: AuthArgs): Promise<AuthRes
88
const { headers, req } = options
99

1010
return await authOperation({
11+
canSetHeaders: Boolean(options.canSetHeaders),
1112
headers,
1213
req: await createLocalReq({ req }, payload),
1314
})

packages/payload/src/auth/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ type GenerateForgotPasswordEmailSubject<TUser = any> = (args?: {
158158
}) => Promise<string> | string
159159

160160
export type AuthStrategyFunctionArgs = {
161+
/**
162+
* Specifies whether or not response headers can be set from this strategy.
163+
*/
164+
canSetHeaders?: boolean
161165
headers: Request['headers']
162166
isGraphQL?: boolean
163167
payload: Payload

packages/payload/src/utilities/createPayloadRequest.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { getRequestLanguage } from './getRequestLanguage.js'
1313
import { parseCookies } from './parseCookies.js'
1414

1515
type Args = {
16+
canSetHeaders?: boolean
1617
config: Promise<SanitizedConfig> | SanitizedConfig
1718
params?: {
1819
collection: string
@@ -21,6 +22,7 @@ type Args = {
2122
}
2223

2324
export const createPayloadRequest = async ({
25+
canSetHeaders,
2426
config: configPromise,
2527
params,
2628
request,
@@ -105,6 +107,7 @@ export const createPayloadRequest = async ({
105107
req.payloadDataLoader = getDataLoader(req)
106108

107109
const { responseHeaders, user } = await executeAuthStrategies({
110+
canSetHeaders,
108111
headers: req.headers,
109112
isGraphQL,
110113
payload,

packages/payload/src/utilities/handleEndpoints.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ export const handleEndpoints = async ({
104104
}
105105

106106
try {
107-
req = await createPayloadRequest({ config: incomingConfig, request })
107+
req = await createPayloadRequest({ canSetHeaders: true, config: incomingConfig, request })
108108

109109
if (req.method.toLowerCase() === 'options') {
110110
return Response.json(

0 commit comments

Comments
 (0)