Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(dbauth-mw): Use response passed in to middleware #10516

Merged
merged 4 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changesets/10516.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- fix(dbauth-mw): Use response passed in to middleware (#10516) by @dac09

Middleware can be chained - which means if auth middleware is not the first one on the list of middleware being registered, we need to use the `MiddlewareResponse` that gets passed to the middleware, instead of creating a new one.
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import path from 'node:path'

import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest'
import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'

import type { MiddlewareRequest } from '@redwoodjs/vite/middleware'
import { MiddlewareRequest as MWRequest } from '@redwoodjs/vite/middleware'
import {
MiddlewareRequest as MWRequest,
MiddlewareRequest,
} from '@redwoodjs/vite/middleware'

import { createDbAuthMiddleware } from '../index'
import type { DbAuthMiddlewareOptions } from '../index'
import { createDbAuthMiddleware } from '../index'
const FIXTURE_PATH = path.resolve(
__dirname,
'../../../../../../__fixtures__/example-todo-main',
Expand All @@ -21,7 +23,7 @@ afterAll(() => {
})

describe('createDbAuthMiddleware()', () => {
it('creates middleware for dbAuth cookie auth', async () => {
it('When no cookie headers, pass through the response', async () => {
const options: DbAuthMiddlewareOptions = {
cookieName: '8911',
getCurrentUser: async () => {
Expand All @@ -42,12 +44,57 @@ describe('createDbAuthMiddleware()', () => {
url: 'http://localhost:8911',
} as MiddlewareRequest

const res = await middleware(req)
// Typecase for the test
const res = await middleware(req, { passthrough: true } as any)

expect(res).toBeDefined()
expect(res).toEqual({ passthrough: true })
})

it('When it has a cookie header, decrypts and sets server auth context', async () => {
const cookieHeader =
'session=ko6iXKV11DSjb6kFJ4iwcf1FEqa5wPpbL1sdtKiV51Y=|cQaYkOPG/r3ILxWiFiz90w=='

const options: DbAuthMiddlewareOptions = {
cookieName: '8911',
getCurrentUser: vi.fn(async () => {
return { id: 'mocked-current-user-1', email: 'user-1@example.com' }
}),
dbAuthHandler: vi.fn(),
}
const middleware = createDbAuthMiddleware(options)

const mwReq = new MiddlewareRequest(
new Request('http://localhost:8911', {
method: 'GET',
headers: {
Cookie: cookieHeader,
},
}),
)

const res = await middleware(mwReq)

expect(mwReq.serverAuthContext.get()).toEqual({
cookieHeader:
'session=ko6iXKV11DSjb6kFJ4iwcf1FEqa5wPpbL1sdtKiV51Y=|cQaYkOPG/r3ILxWiFiz90w==',
currentUser: {
email: 'user-1@example.com',
id: 'mocked-current-user-1',
},
hasError: false,
isAuthenticated: true,
loading: false,
userMetadata: {
email: 'user-1@example.com',
id: 'mocked-current-user-1',
},
})

// Allow react render, because body is not defined, and status code not redirect
expect(res).toHaveProperty('body', undefined)
expect(res).toHaveProperty('status', 200)
})

describe('handle all supported dbAuth verbs (aka methods) and their HTTP methods', async () => {
/**
* Supported verbs and their corresponding HTTP methods:
Expand Down Expand Up @@ -405,6 +452,7 @@ describe('createDbAuthMiddleware()', () => {
expect(res).toBeDefined()
expect(res.body).toBe(JSON.stringify({ currentUser }))
})

describe('handle exception cases', async () => {
it('handles a POST that is not one of the supported dbAuth verbs and still build headers when passing along the request', async () => {
const request = new Request(
Expand Down Expand Up @@ -487,7 +535,7 @@ describe('createDbAuthMiddleware()', () => {
user: { id: 100, email: 'hello@example.com' },
})
})
it('handles a GET request with no cookies', async () => {})

it('handles a GET request with incorrect cookies (bad decrypt)', async () => {
const request = new Request(
'http://localhost:8911/functions/bad-cookie',
Expand All @@ -500,7 +548,7 @@ describe('createDbAuthMiddleware()', () => {
},
)

const req = new MWRequest(request)
const mwReq = new MWRequest(request)

const options: DbAuthMiddlewareOptions = {
cookieName: 'session_8911',
Expand All @@ -517,10 +565,10 @@ describe('createDbAuthMiddleware()', () => {
}
const middleware = createDbAuthMiddleware(options)

const res = await middleware(req)
const res = await middleware(mwReq)
expect(res).toBeDefined()

const serverAuthContext = req.serverAuthContext.get()
const serverAuthContext = mwReq.serverAuthContext.get()
expect(serverAuthContext).toBeNull()

expect(res.toResponse().headers.getSetCookie()).toEqual([
Expand All @@ -529,6 +577,7 @@ describe('createDbAuthMiddleware()', () => {
'auth-provider=; Expires=Thu, 01 Jan 1970 00:00:00 GMT',
])
})

it('handles a GET request with no cookies', async () => {
const request = new Request('http://localhost:8911/functions/no-cookie', {
method: 'GET',
Expand Down
7 changes: 4 additions & 3 deletions packages/auth-providers/dbAuth/middleware/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ export const createDbAuthMiddleware = ({
getCurrentUser,
dbAuthUrl = '/middleware/dbauth',
}: DbAuthMiddlewareOptions) => {
return async (req: MiddlewareRequest) => {
const res = MiddlewareResponse.next()

return async (
req: MiddlewareRequest,
res: MiddlewareResponse = MiddlewareResponse.next(),
) => {
// Handoff POST requests to the dbAuthHandler. The url is configurable on the dbAuth client side.
// This is where we handle login, logout, and signup, etc., but we don't want to intercept
if (req.method === 'POST') {
Expand Down
Loading