From 7bc77ac7d79425ff69a979c333e3289776bebc9f Mon Sep 17 00:00:00 2001 From: Jonathan Bernard Date: Tue, 4 Feb 2025 17:54:07 -0600 Subject: [PATCH] Allow bypassing of CSRF valdiation when needed. --- buffoonery.nimble | 2 +- src/buffoonery/auth.nim | 19 +++++++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/buffoonery.nimble b/buffoonery.nimble index ad40e71..4cff2f0 100644 --- a/buffoonery.nimble +++ b/buffoonery.nimble @@ -1,6 +1,6 @@ # Package -version = "0.4.5" +version = "0.4.6" author = "Jonathan Bernard" description = "Jonathan's opinionated extensions and auth layer for Jester." license = "MIT" diff --git a/src/buffoonery/auth.nim b/src/buffoonery/auth.nim index ab6eb3d..bb46384 100644 --- a/src/buffoonery/auth.nim +++ b/src/buffoonery/auth.nim @@ -167,7 +167,7 @@ proc validateJWT*(ctx: ApiAuthContext, jwt: JWT) = failAuth(getCurrentExceptionMsg(), getCurrentException()) -proc extractValidJwt*(ctx: ApiAuthContext, req: Request): JWT = +proc extractValidJwt*(ctx: ApiAuthContext, req: Request, validateCsrf = true): JWT = ## Extracts a valid JWT representing the user's authentication and ## authorization details, if present. If there are no valid credentials an ## exception is raised. @@ -191,6 +191,12 @@ proc extractValidJwt*(ctx: ApiAuthContext, req: Request): JWT = ## ## In the split-cookie mode we also check that the `csrfToken` claim in the ## JWT payload matches the CSRF value passed via the `X-CSRF-TOKEN` header. + ## This CSRF check can be disabled by setting `validateCsrf` to `false`. + ## This option is proivded to support occasional use-cases where you want to + ## be able to serve a request using cookie auth when the client can't set + ## custom headers (e.g. a simple link from an tag). Obviously, this is a + ## security risk and should only be used with caution with a full + ## understanding of the risk. try: if req.headers.contains("Authorization"): @@ -214,12 +220,13 @@ proc extractValidJwt*(ctx: ApiAuthContext, req: Request): JWT = # Because this is a web session, check that the CSRF is present and # matches. - if not req.headers.contains("X-CSRF-TOKEN") or - not result.claims["csrfToken"].isSome: - failAuth "missing CSRF token" + if validateCsrf: + if not req.headers.contains("X-CSRF-TOKEN") or + not result.claims["csrfToken"].isSome: + failAuth "missing CSRF token" - if req.headers["X-CSRF-TOKEN"] != result.claims["csrfToken"].get.getStr(""): - failAuth "invalid CSRF token" + if req.headers["X-CSRF-TOKEN"] != result.claims["csrfToken"].get.getStr(""): + failAuth "invalid CSRF token" else: failAuth "no auth token, no Authorization or Cookie headers"