@@ -9,10 +9,13 @@ module Csrf =
99 open System
1010 open System.Security .Cryptography
1111 open System.Text
12+ open System.Threading .Tasks
1213 open Microsoft.AspNetCore .Http
1314 open Microsoft.Extensions .Logging
1415 open Microsoft.AspNetCore .Antiforgery
1516
17+ // Defaults are selected to what developers would expect from ASP.NET Core application.
18+
1619 /// <summary >
1720 /// Default CSRF token header name
1821 /// </summary >
@@ -29,36 +32,67 @@ module Csrf =
2932 /// Validates the CSRF token from the request.
3033 /// Checks for token in header (X-CSRF-TOKEN) or form field (__ RequestVerificationToken).
3134 /// </summary >
35+ /// <param name =" invalidTokenHandler " >Optional custom handler for invalid tokens. If None, returns 403 Forbidden with logged warning.</param >
3236 /// <param name =" next " >The next HttpFunc</param >
3337 /// <param name =" ctx " >The HttpContext</param >
3438 /// <returns >HttpFuncResult</returns >
35- let validateCsrfToken : HttpHandler =
39+ let validateCsrfTokenExt ( invalidTokenHandler : HttpHandler option ) : HttpHandler =
3640 fun ( next : HttpFunc ) ( ctx : HttpContext ) ->
3741 task {
3842 let antiforgery = ctx.GetService< IAntiforgery>()
3943
4044 try
41- let! isValid = antiforgery.IsRequestValidAsync( ctx)
45+ let! isValid = antiforgery.IsRequestValidAsync ctx
4246
4347 if isValid then
4448 return ! next ctx
4549 else
46- let logger = ctx.GetLogger( " Giraffe.Csrf" )
47- logger.LogWarning( " CSRF token validation failed for request to {Path}" , ctx.Request.Path)
48- ctx.Response.StatusCode <- 403
49- return Some ctx
50+ let defaultHandler =
51+ fun ( next : HttpFunc ) ( ctx : HttpContext ) ->
52+ let logger = ctx.GetLogger( " Giraffe.Csrf" )
53+
54+ logger.LogWarning(
55+ " CSRF token validation failed for request to {Path}" ,
56+ ctx.Request.Path
57+ )
58+
59+ ctx.Response.StatusCode <- 403
60+ Task.FromResult( Some ctx)
61+
62+ let handler = invalidTokenHandler |> Option.defaultValue defaultHandler
63+ return ! handler earlyReturn ctx
5064 with ex ->
51- let logger = ctx.GetLogger( " Giraffe.Csrf" )
52- logger.LogWarning( ex, " CSRF token validation error for request to {Path}" , ctx.Request.Path)
53- ctx.Response.StatusCode <- 403
54- return Some ctx
65+ let defaultHandler =
66+ fun ( next : HttpFunc ) ( ctx : HttpContext ) ->
67+ let logger = ctx.GetLogger( " Giraffe.Csrf" )
68+ logger.LogWarning( ex, " CSRF token validation error for request to {Path}" , ctx.Request.Path)
69+ ctx.Response.StatusCode <- 403
70+ Task.FromResult( Some ctx)
71+
72+ let handler = invalidTokenHandler |> Option.defaultValue defaultHandler
73+ return ! handler earlyReturn ctx
5574 }
5675
76+ /// <summary >
77+ /// Validates the CSRF token from the request with default error handling.
78+ /// Checks for token in header (X-CSRF-TOKEN) or form field (__ RequestVerificationToken).
79+ /// Uses default error handling (403 Forbidden) for invalid tokens.
80+ /// </summary >
81+ /// <param name =" next " >The next HttpFunc</param >
82+ /// <param name =" ctx " >The HttpContext</param >
83+ /// <returns >HttpFuncResult</returns >
84+ let validateCsrfToken : HttpHandler = validateCsrfTokenExt None
85+
5786 /// <summary >
5887 /// Alias for validateCsrfToken - validates anti-forgery tokens from requests.
5988 /// </summary >
6089 let requireAntiforgeryToken = validateCsrfToken
6190
91+ /// <summary >
92+ /// Alias for validateCsrfTokenExt - validates anti-forgery tokens from requests with custom error handler.
93+ /// </summary >
94+ let requireAntiforgeryTokenExt = validateCsrfTokenExt
95+
6296 /// <summary >
6397 /// Generates a CSRF token and adds it to the HttpContext items for use in views.
6498 /// The token can be accessed via ctx.Items[ "CsrfToken"] and ctx.Items[ "CsrfTokenHeaderName"] .
@@ -70,7 +104,7 @@ module Csrf =
70104 fun ( next : HttpFunc ) ( ctx : HttpContext ) ->
71105 task {
72106 let antiforgery = ctx.GetService< IAntiforgery>()
73- let tokens = antiforgery.GetAndStoreTokens( ctx)
107+ let tokens = antiforgery.GetAndStoreTokens ctx
74108
75109 // Store token for view rendering
76110 ctx.Items.[ " CsrfToken" ] <- tokens.RequestToken
@@ -90,7 +124,7 @@ module Csrf =
90124 fun ( next : HttpFunc ) ( ctx : HttpContext ) ->
91125 task {
92126 let antiforgery = ctx.GetService< IAntiforgery>()
93- let tokens = antiforgery.GetAndStoreTokens( ctx)
127+ let tokens = antiforgery.GetAndStoreTokens ctx
94128
95129 let response =
96130 {|
0 commit comments