diff --git a/routers/init.go b/routers/init.go
index 423276c1bf..e70525913c 100644
--- a/routers/init.go
+++ b/routers/init.go
@@ -169,12 +169,12 @@ func InitWebInstalled(ctx context.Context) {
 }
 
 // NormalRoutes represents non install routes
-func NormalRoutes() *web.Route {
+func NormalRoutes(middlewares ...any) *web.Route {
 	_ = templates.HTMLRenderer()
 	r := web.NewRoute()
 	r.Use(common.ProtocolMiddlewares()...)
 
-	r.Mount("/", web_routers.Routes())
+	r.Mount("/", web_routers.Routes(middlewares...))
 	r.Mount("/api/v1", apiv1.Routes())
 	r.Mount("/api/forgejo/v1", forgejo.Routes())
 	r.Mount("/api/internal", private.Routes())
diff --git a/routers/web/web.go b/routers/web/web.go
index 1ee0a5d91e..4328272e20 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -104,7 +104,7 @@ func ctxDataSet(args ...any) func(ctx *context.Context) {
 }
 
 // Routes returns all web routes
-func Routes() *web.Route {
+func Routes(middlewares ...any) *web.Route {
 	routes := web.NewRoute()
 
 	routes.Head("/", misc.DummyOK) // for health check - doesn't need to be passed through gzip handler
@@ -162,6 +162,7 @@ func Routes() *web.Route {
 	mid = append(mid, user.GetNotificationCount)
 	mid = append(mid, repo.GetActiveStopwatch)
 	mid = append(mid, goGet)
+	mid = append(mid, middlewares...)
 
 	others := web.NewRoute()
 	others.Use(mid...)
diff --git a/tests/integration/api_activitypub_person_test.go b/tests/integration/api_activitypub_person_test.go
index a1ce802709..140cf0f034 100644
--- a/tests/integration/api_activitypub_person_test.go
+++ b/tests/integration/api_activitypub_person_test.go
@@ -14,7 +14,6 @@ import (
 	user_model "code.gitea.io/gitea/models/user"
 	"code.gitea.io/gitea/modules/activitypub"
 	"code.gitea.io/gitea/modules/setting"
-	"code.gitea.io/gitea/routers"
 
 	ap "github.com/go-ap/activitypub"
 	"github.com/stretchr/testify/assert"
@@ -22,10 +21,10 @@ import (
 
 func TestActivityPubPerson(t *testing.T) {
 	setting.Federation.Enabled = true
-	c = routers.NormalRoutes()
+	setNormalRoutes()
 	defer func() {
 		setting.Federation.Enabled = false
-		c = routers.NormalRoutes()
+		setNormalRoutes()
 	}()
 
 	onGiteaRun(t, func(*testing.T, *url.URL) {
@@ -60,10 +59,10 @@ func TestActivityPubPerson(t *testing.T) {
 
 func TestActivityPubMissingPerson(t *testing.T) {
 	setting.Federation.Enabled = true
-	c = routers.NormalRoutes()
+	setNormalRoutes()
 	defer func() {
 		setting.Federation.Enabled = false
-		c = routers.NormalRoutes()
+		setNormalRoutes()
 	}()
 
 	onGiteaRun(t, func(*testing.T, *url.URL) {
@@ -75,10 +74,10 @@ func TestActivityPubMissingPerson(t *testing.T) {
 
 func TestActivityPubPersonInbox(t *testing.T) {
 	setting.Federation.Enabled = true
-	c = routers.NormalRoutes()
+	setNormalRoutes()
 	defer func() {
 		setting.Federation.Enabled = false
-		c = routers.NormalRoutes()
+		setNormalRoutes()
 	}()
 
 	srv := httptest.NewServer(c)
diff --git a/tests/integration/api_nodeinfo_test.go b/tests/integration/api_nodeinfo_test.go
index 158a866091..3052d95be0 100644
--- a/tests/integration/api_nodeinfo_test.go
+++ b/tests/integration/api_nodeinfo_test.go
@@ -10,17 +10,16 @@ import (
 
 	"code.gitea.io/gitea/modules/setting"
 	api "code.gitea.io/gitea/modules/structs"
-	"code.gitea.io/gitea/routers"
 
 	"github.com/stretchr/testify/assert"
 )
 
 func TestNodeinfo(t *testing.T) {
 	setting.Federation.Enabled = true
-	c = routers.NormalRoutes()
+	setNormalRoutes()
 	defer func() {
 		setting.Federation.Enabled = false
-		c = routers.NormalRoutes()
+		setNormalRoutes()
 	}()
 
 	onGiteaRun(t, func(*testing.T, *url.URL) {
diff --git a/tests/integration/create_no_session_test.go b/tests/integration/create_no_session_test.go
index 535d0d4955..81e02e3c2c 100644
--- a/tests/integration/create_no_session_test.go
+++ b/tests/integration/create_no_session_test.go
@@ -12,7 +12,6 @@ import (
 
 	"code.gitea.io/gitea/modules/json"
 	"code.gitea.io/gitea/modules/setting"
-	"code.gitea.io/gitea/routers"
 	"code.gitea.io/gitea/tests"
 
 	"gitea.com/go-chi/session"
@@ -56,7 +55,7 @@ func TestSessionFileCreation(t *testing.T) {
 	oldSessionConfig := setting.SessionConfig.ProviderConfig
 	defer func() {
 		setting.SessionConfig.ProviderConfig = oldSessionConfig
-		c = routers.NormalRoutes()
+		setNormalRoutes()
 	}()
 
 	var config session.Options
@@ -75,7 +74,7 @@ func TestSessionFileCreation(t *testing.T) {
 
 	setting.SessionConfig.ProviderConfig = string(newConfigBytes)
 
-	c = routers.NormalRoutes()
+	setNormalRoutes()
 
 	t.Run("NoSessionOnViewIssue", func(t *testing.T) {
 		defer tests.PrintCurrentTest(t)()
diff --git a/tests/integration/integration_test.go b/tests/integration/integration_test.go
index c904d32ffa..9bd603a6cc 100644
--- a/tests/integration/integration_test.go
+++ b/tests/integration/integration_test.go
@@ -40,7 +40,19 @@ import (
 	"github.com/xeipuuv/gojsonschema"
 )
 
-var c *web.Route
+var (
+	c                  *web.Route
+	testMiddlewareHook func(*gitea_context.Context)
+)
+
+func setNormalRoutes() {
+	middlewareHook := func(ctx *gitea_context.Context) {
+		if testMiddlewareHook != nil {
+			testMiddlewareHook(ctx)
+		}
+	}
+	c = routers.NormalRoutes(middlewareHook)
+}
 
 type NilResponseRecorder struct {
 	httptest.ResponseRecorder
@@ -87,8 +99,7 @@ func TestMain(m *testing.M) {
 	defer cancel()
 
 	tests.InitTest(true)
-	c = routers.NormalRoutes()
-
+	setNormalRoutes()
 	// integration test settings...
 	if setting.CfgProvider != nil {
 		testingCfg := setting.CfgProvider.Section("integration-tests")