diff --git a/.changeset/great-toys-knock.md b/.changeset/great-toys-knock.md new file mode 100644 index 00000000..6c95a505 --- /dev/null +++ b/.changeset/great-toys-knock.md @@ -0,0 +1,5 @@ +--- +'@hono/auth-js': patch +--- + +fix(auth-js): use HonoRequest.blob() instead of HonoRequest.raw.body() diff --git a/packages/auth-js/src/index.test.ts b/packages/auth-js/src/index.test.ts index cfd82224..71eac417 100644 --- a/packages/auth-js/src/index.test.ts +++ b/packages/auth-js/src/index.test.ts @@ -2,6 +2,7 @@ import { skipCSRFCheck } from '@auth/core' import type { Adapter } from '@auth/core/adapters' import Credentials from '@auth/core/providers/credentials' import { Hono } from 'hono' +import { validator } from 'hono/validator' import { describe, expect, it, vi } from 'vitest' import type { AuthConfig } from '.' import { authHandler, verifyAuth, initAuthConfig, reqWithEnvUrl } from '.' @@ -80,6 +81,128 @@ describe('reqWithEnvUrl()', async () => { it('Should rewrite the base path', () => { expect(newReq.url.toString()).toBe('https://auth-url-base/request-path') }) + + const mockAdapter: Adapter = { + createVerificationToken: vi.fn(), + useVerificationToken: vi.fn(), + getUserByEmail: vi.fn(), + createUser: vi.fn(), + getUser: vi.fn(), + getUserByAccount: vi.fn(), + updateUser: vi.fn(), + linkAccount: vi.fn(), + createSession: vi.fn(), + getSessionAndUser: vi.fn(), + updateSession: vi.fn(), + deleteSession: vi.fn(), + } + + globalThis.process.env = { + AUTH_SECRET: 'secret', + } + + const user = { email: 'hono@hono.hono', name: 'Hono' } + + const credentials = Credentials({ + credentials: { + password: {}, + }, + authorize: (credentials) => { + if (credentials.password === 'password') { + return user + } + return null + }, + }) + + function getAuthConfig(): AuthConfig { + return { + secret: 'secret', + providers: [credentials], + adapter: mockAdapter, + basePath: '/api/auth', + callbacks: { + jwt: ({ token, user }) => { + if (user) { + token.id = user.id + } + return token + }, + }, + session: { + strategy: 'jwt', + }, + } + } + + let cookie = [''] + + it('Should be able to instantiate new Request after passing through validator', async () => { + const app = new Hono() + + app.use('*', initAuthConfig(getAuthConfig)) + app.use( + '/api/auth/*', + validator('form', (value, _) => { + const csrfToken = value['csrfToken'] + return { + csrfToken, + } + }), + authHandler() + ) + + let csrfRes = await app.request('http://localhost/api/auth/csrf', { + method: 'GET', + }) + let { csrfToken } = await csrfRes.json() + + cookie = csrfRes.headers.getSetCookie() + + let headers = new Headers() + headers.append('cookie', cookie[0]) + + const signInRes = await app.request('http://localhost/api/auth/callback/credentials', { + method: 'POST', + headers, + body: new URLSearchParams({ + csrfToken, + password: 'password', + }), + }) + expect(signInRes.status).toBe(302) + expect(signInRes.headers.get('location')).toBe('http://localhost') + + cookie = signInRes.headers.getSetCookie() + + const sessionCookie = cookie[1] + + headers = new Headers() + headers.append('cookie', cookie[1]) + headers.append('Content-Type', 'application/json') + + csrfRes = await app.request('http://localhost/api/auth/csrf', { + method: 'GET', + }) + ;({ csrfToken } = await csrfRes.json()) + + cookie = csrfRes.headers.getSetCookie() + + headers = new Headers() + headers.append('cookie', cookie[0]) + headers.append('cookie', sessionCookie) + + const req = new Request('http://localhost/api/auth/signout', { + method: 'POST', + body: new URLSearchParams({ + csrfToken, + password: 'password', + }), + headers, + }) + const res = await app.request(req) + expect(res.status).toBe(302) + }) }) describe('Credentials Provider', () => { diff --git a/packages/auth-js/src/index.ts b/packages/auth-js/src/index.ts index ca0875a9..0944203c 100644 --- a/packages/auth-js/src/index.ts +++ b/packages/auth-js/src/index.ts @@ -135,7 +135,27 @@ export function authHandler(): MiddlewareHandler { throw new HTTPException(500, { message: 'Missing AUTH_SECRET' }) } - const res = await Auth(reqWithEnvUrl(c.req.raw, ctxEnv.AUTH_URL), config) + const body = c.req.raw.body ? await c.req.blob() : undefined + const res = await Auth( + reqWithEnvUrl( + new Request(c.req.raw.url, { + body, + cache: c.req.raw.cache, + credentials: c.req.raw.credentials, + headers: c.req.raw.headers, + integrity: c.req.raw.integrity, + keepalive: c.req.raw.keepalive, + method: c.req.raw.method, + mode: c.req.raw.mode, + redirect: c.req.raw.redirect, + referrer: c.req.raw.referrer, + referrerPolicy: c.req.raw.referrerPolicy, + signal: c.req.raw.signal, + }), + ctxEnv.AUTH_URL + ), + config + ) return new Response(res.body, res) } }