Open cdubz opened 1 month ago
Hi @cdubz I dug into the code and it might be that underneath we're looking for a WHATWG Request vs http or Node Request. See: https://github.com/redwoodjs/redwood/blob/4a7b887976810b75facfdf65b621d65e3aa5f3dc/packages/api/src/transforms.ts#L1
import { Headers, Request as PonyfillRequest } from '@whatwg-node/fetch'
It could be that when getting the event header here https://github.com/redwoodjs/redwood/blob/4a7b887976810b75facfdf65b621d65e3aa5f3dc/packages/api/src/transforms.ts#L46 perhaps the Request is of a different type?
Worth trying?
If so, we should fix that type to be clearer.
Ah, yeah I didn't notice that.
We're integrating the useResponseCache
plugin for the GraphQL handler and that is giving us a Node Request at the point where we want to set up a session ID: https://github.com/dotansimha/graphql-yoga/blob/9efdc3831a517890dbb00c783d6da86c6a6d9b4e/packages/plugins/response-cache/src/index.ts#L28
We're having to get the auth provider here because we are using a custom provider alongside dbAuth
.
It does work for us with getEventHeader
but only if we manually put in Auth-Provider
because the AUTH_PROVIDER_HEADER
const is all lowercase and getEventHeader
only supports either of the provided casing or all lowercase
import { getEventHeader } from '@redwoodjs/api'
const authProvider = getEventHeader(request, 'Auth-Provider')
Re: isFetchApiRequest
-- we don't get to it because getAuthProviderHeader
doesn't find the header.
I was wondering if it would make sense to adjust getEventHeader
to support any casing for headers (e.g., make Auth-Provider
, auth-provider
, AUTH-PROVIDER
all match) and then just use that in getAuthProviderHeader
instead of the Object.keys
handling? Maybe I'm missing some other issue there.
We're integrating the
useResponseCache
plugin for the GraphQL handler
Interesting -- the reason we use the WHATWG request is in fact because that's what the Guild uses in all GraphQL Yoga.
This https://github.com/ardatan/whatwg-node is managed by Arda from The Guild -- so I'd have though them to be compatible.
I'll ask.
const operationId = request.headers.get('If-None-Match');
Maybe it this case since it is custom auth, it makes sense just to get the raw request headers and authorize?
That said when I look at:
export const getAuthProviderHeader = (
event: APIGatewayProxyEvent | Request,
) => {
const authProviderKey = Object.keys(event?.headers ?? {}).find(
(key) => key.toLowerCase() === AUTH_PROVIDER_HEADER,
)
if (authProviderKey) {
return getEventHeader(event, authProviderKey)
}
return undefined
}
and your
const authProvider = getEventHeader(request, 'Auth-Provider')
Seems like should work.
Have you tried:
const testRequest = new Request('https://redwoodjs.com/', {
headers: {
'auth-provider': 'test',
},
});
or
testRequest.headers.set('auth-provider', 'test');
But append should mutate the headers in place so kind of scratching my head why.
I still think just getting headers on own for this custom auth may make sense -- at least add a workaround? until we can identify the cause and fix? Maybe?
To be clear -- getAuthProviderHeader
should indeed work. The issue is just that it doesn't work with a plain NodeJS request object.
The alternative approach uses getEventHeader
which looks like this:
export const getEventHeader = (
event: APIGatewayProxyEvent | Request,
headerName: string,
) => {
if (isFetchApiRequest(event)) {
return event.headers.get(headerName)
}
return event.headers[headerName] || event.headers[headerName.toLowerCase()]
}
It is only checking for headerName
exactly as provided or all lower case. So
const authProvider = getEventHeader(request, 'Auth-Provider')
works fine, but
const authProvider = getEventHeader(request, AUTH_PROVIDER_HEADER)
does not work (if the header is anything other than exactly auth-provider
).
It's a minor thing really, but it might be nice to adjust getEventHeader
to do something more like getAuthProviderHeader
:
export const getEventHeader = (
event: APIGatewayProxyEvent | Request,
headerName: string,
) => {
if (isFetchApiRequest(event)) {
return event.headers.get(headerName)
}
const headerKey = Object.keys(event?.headers ?? {}).find(
(key) => key.toLowerCase() === headerName.toLowerCase(),
)
return headerKey ? event.headers[headerKey] : undefined
}
And from there getAuthProviderHeader
could even be adjusted to just do this:
export const getAuthProviderHeader = (
event: APIGatewayProxyEvent | Request,
) => getEventHeader(event, AUTH_PROVIDER_HEADER)
This would make things work regardless of the casing of the passed in headerName
(I think, didn't actually test 😁).
I still think just getting headers on own for this custom auth may make sense -- at least add a workaround? until we can identify the cause and fix? Maybe?
Yes, absolutely. That is what I'm doing and it's really fine. Just trying to think if we can improve these helpful utilities.
Just trying to think if we can improve these helpful utilities.
Agreed! Any many thanks for the feedback and suggestions.
I like this change and makes sense --- and tons cleaner.
I'll share with team!
Sounds good! Note I just made a small edit to fix my example code. I was returning the key name not it's value 🤦
What's not working?
The current definition of
getAuthProviderHeader
says it supports getting the auth provider header from aAPIGatewayProxyEvent
orRequest
:This works as expected for
APIGatewayProxyEvent
, but not forRequest
.How do we reproduce the bug?
In the above example,
authProvider
should betest
, but it isundefined
.What's your environment? (If it applies)
Are you interested in working on this?