Skip to content

Commit c1531f6

Browse files
committed
feat: generate and share csrf token on error as well
1 parent 8cf32c6 commit c1531f6

File tree

2 files changed

+42
-10
lines changed

2 files changed

+42
-10
lines changed

src/guards/csrf.ts

+10-10
Original file line numberDiff line numberDiff line change
@@ -197,16 +197,6 @@ export class CsrfGuard {
197197
async handle(ctx: HttpContext): Promise<void> {
198198
const csrfSecret = await this.#getCsrfSecret(ctx)
199199

200-
/**
201-
* Validate current request before moving forward
202-
*/
203-
if (this.#shouldValidateRequest(ctx)) {
204-
const csrfToken = this.#getCsrfTokenFromRequest(ctx)
205-
if (!csrfToken || !this.#tokens.verify(csrfSecret, csrfToken)) {
206-
throw new E_BAD_CSRF_TOKEN()
207-
}
208-
}
209-
210200
/**
211201
* Add csrf token on the request
212202
*/
@@ -226,6 +216,16 @@ export class CsrfGuard {
226216
* Share with the view engine
227217
*/
228218
this.#shareCsrfViewLocals(ctx)
219+
220+
/**
221+
* Validate current request before moving forward
222+
*/
223+
if (this.#shouldValidateRequest(ctx)) {
224+
const csrfToken = this.#getCsrfTokenFromRequest(ctx)
225+
if (!csrfToken || !this.#tokens.verify(csrfSecret, csrfToken)) {
226+
throw new E_BAD_CSRF_TOKEN()
227+
}
228+
}
229229
}
230230
}
231231

tests/csrf.spec.ts

+32
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,38 @@ test.group('Csrf', () => {
328328
)
329329
})
330330

331+
test('share CSRF token with templates and request even when request fails', async ({
332+
assert,
333+
}) => {
334+
const app = await setup()
335+
const ctx = new HttpContextFactory().create()
336+
const encrpytion = await app.container.make('encryption')
337+
const middleware = await new SessionMiddlewareFactory().create()
338+
339+
await middleware.handle(ctx, async () => {
340+
ctx.route = { pattern: '/' } as any
341+
ctx.request.request.method = 'PATCH'
342+
343+
const secret = await tokens.secret()
344+
const csrfToken = tokens.create(secret)
345+
ctx.request.updateBody({ _csrf: csrfToken })
346+
})
347+
348+
const csrf = csrfFactory({ enabled: true, enableXsrfCookie: false }, encrpytion, Edge.create())
349+
await assert.rejects(async () => csrf(ctx), new E_BAD_CSRF_TOKEN().message)
350+
assert.exists(ctx.request.csrfToken)
351+
352+
assert.equal(
353+
await ctx.view.renderRaw('{{ csrfMeta() }}'),
354+
`<meta name='csrf-token' content='${ctx.request.csrfToken}'>`
355+
)
356+
357+
assert.equal(
358+
await ctx.view.renderRaw('{{ csrfField() }}'),
359+
`<input type='hidden' name='_csrf' value='${ctx.request.csrfToken}'>`
360+
)
361+
})
362+
331363
test('generate csrf token and share as a cookie when enableXsrfCookie is true', async ({
332364
assert,
333365
}) => {

0 commit comments

Comments
 (0)