Skip to content

Commit

Permalink
Get it working with middleware!
Browse files Browse the repository at this point in the history
  • Loading branch information
dac09 committed Dec 22, 2023
1 parent 3f0a32b commit 0979725
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 15 deletions.
45 changes: 44 additions & 1 deletion packages/api/src/auth/__tests__/getAuthenticationContext.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,4 +212,47 @@ describe('getAuthenticationContext with bearer tokens', () => {
})

// @TODO add tests for requests with Cookie headers
describe('getAuthenticationContext with cookies', () => {})
describe('getAuthenticationContext with cookies', () => {
it('Can take a single auth decoder for the given provider', async () => {
const authDecoderOne = async (_token: string, type: string) => {
if (type !== 'one') {
return null
}

return {
iss: 'one',
sub: 'user-id',
}
}

const fetchRequest = new Request('http://localhost:3000', {
method: 'POST',
body: '',
headers: {
cookie: 'auth-provider=one; session=xx/yy/zz',
},
})

const result = await getAuthenticationContext({
authDecoder: authDecoderOne,
event: fetchRequest,
context: {} as Context,
})

if (!result) {
fail('Result is undefined')
}

const [decoded, { type, schema, token }] = result

expect(decoded).toMatchObject({
iss: 'one',
sub: 'user-id',
})
expect(type).toEqual('one')
expect(schema).toEqual('cookie')
// @TODO we need to rename this. It's not actually the token, because
// some auth providers will have a cookie where we don't know the key
expect(token).toEqual('auth-provider=one; session=xx/yy/zz')
})
})
26 changes: 18 additions & 8 deletions packages/api/src/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,16 @@ export type { Decoded }
// This is shared by `@redwoodjs/web`
const AUTH_PROVIDER_HEADER = 'auth-provider'

export const getAuthProviderHeader = (event: APIGatewayProxyEvent) => {
export const getAuthProviderHeader = (
event: APIGatewayProxyEvent | Request
) => {
const authProviderKey = Object.keys(event?.headers ?? {}).find(
(key) => key.toLowerCase() === AUTH_PROVIDER_HEADER
)
if (authProviderKey) {
return event?.headers[authProviderKey]
return isFetchApiRequest(event)
? event?.headers.get(authProviderKey)
: event?.headers[authProviderKey]
}
return undefined
}
Expand All @@ -44,7 +48,7 @@ export const parseAuthorizationCookie = (
return {
parsedCookie,
rawCookie: cookie,
type: parsedCookie.authProvider,
type: parsedCookie['auth-provider'],
}
}

Expand Down Expand Up @@ -89,11 +93,11 @@ export const getAuthenticationContext = async ({
context,
}: {
authDecoder?: Decoder | Decoder[]
event: APIGatewayProxyEvent
event: APIGatewayProxyEvent | Request
context: LambdaContext
}): Promise<undefined | AuthContextPayload> => {
const typeFromHeader = getAuthProviderHeader(event)
const cookieHeader = parseAuthorizationCookie(event)
const cookieHeader = parseAuthorizationCookie(event) //?

// Shortcircuit - if no auth-provider or cookie header, its
// an unauthenticated request
Expand All @@ -107,7 +111,7 @@ export const getAuthenticationContext = async ({

// If type is set in the header, use Bearer token auth
if (typeFromHeader) {
const parsedAuthHeader = parseAuthorizationHeader(event)
const parsedAuthHeader = parseAuthorizationHeader(event as any)
token = parsedAuthHeader.token
type = typeFromHeader
schema = parsedAuthHeader.schema
Expand Down Expand Up @@ -136,9 +140,15 @@ export const getAuthenticationContext = async ({

let i = 0
while (!decoded && i < authDecoders.length) {
decoded = await authDecoders[i](token, type, { event, context })
decoded = await authDecoders[i](token, type, {
// @TODO We will need to make a breaking change to auth decoders maybe
event: event as any,
context,
})
i++
}

return [decoded, { type, schema, token }, { event, context }]
// @TODO we need to rename this. It's not actually the token, because
// some auth providers will have a cookie where we don't know the key
return [decoded, { type, schema, token }, { event: event as any, context }]
}
15 changes: 14 additions & 1 deletion packages/api/src/transforms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,21 @@ export const parseFetchEventBody = async (event: Request) => {
return body ? JSON.parse(body) : undefined
}

// @TODO
// @TODO
// @TODO
// THis is in a hacked state. Need to figure out why instanceof isn't working in middleware
export const isFetchApiRequest = (event: any): event is Request => {
return event instanceof Request || event instanceof PonyFillRequest
if (event instanceof Request || event instanceof PonyFillRequest) {
return true
}

if (event.httpMethod || event.queryStringParameters) {
return false
}

// @TODO I dont know why instance of Request is not working in middleware
return true
}

function getQueryStringParams(reqUrl: string) {
Expand Down
4 changes: 4 additions & 0 deletions packages/auth-providers/dbAuth/api/src/DbAuthHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,10 @@ export class DbAuthHandler<
this.options = options
this.event = event
this.httpMethod = isFetchApiRequest(event) ? event.method : event.httpMethod
console.log(
`👉 \n ~ file: DbAuthHandler.ts:396 ~ isFetchApiRequest(event):`,
isFetchApiRequest(event)
)

this.cookie = extractCookie(event) || ''

Expand Down
4 changes: 4 additions & 0 deletions packages/auth-providers/dbAuth/web/src/dbAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ export function createDbAuthClient({
body: JSON.stringify({ username, password, method: 'login' }),
})

if (typeof window !== undefined) {
document.cookie = 'auth-provider=dbAuth'
}

return response.json()
}

Expand Down
13 changes: 8 additions & 5 deletions packages/vite/src/devFeServer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Response, createServerAdapter } from '@whatwg-node/server'
import { createServerAdapter } from '@whatwg-node/server'
import express from 'express'
import type { ViteDevServer } from 'vite'
import { createServer as createViteServer } from 'vite'
Expand Down Expand Up @@ -82,7 +82,9 @@ async function createServer() {
app.get(expressPathDef, createServerAdapter(routeHandler))
}

app.post(
// @TODO: DbAuth still sends a GET request for getToken
// Do we still need getToken if gets updated by middleware anyway?
app.all(
'/_rw_mw',
createServerAdapter(async (req: Request) => {
const entryServerImport = await vite.ssrLoadModule(
Expand All @@ -95,13 +97,14 @@ async function createServer() {
if (middleware) {
try {
out = await middleware(req)
console.log(`👉 \n ~ file: devFeServer.ts:97 ~ out:`, out)
} catch (e) {
console.error('Whooopsie, error in middleware', e)
console.error('Whooopsie, error in middleware POST handler')
console.error(e)
}
}

return new Response(out)
// @TODO: We should check the type of resposne here I guess
return out
})
)

Expand Down

0 comments on commit 0979725

Please sign in to comment.