From fa3895ce81ba64689fbf76b91d96963541547881 Mon Sep 17 00:00:00 2001
From: zeripath <art27@cantab.net>
Date: Tue, 6 Apr 2021 20:44:05 +0100
Subject: [PATCH] Move modules/forms to services/forms (#15305)

Forms are dependent on models and therefore should be in services.

This PR also removes the old auth. aliasing

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
---
 .../api_helper_for_declarative_test.go        |   8 +-
 integrations/api_pull_test.go                 |   4 +-
 routers/admin/admin.go                        |   4 +-
 routers/admin/auths.go                        |  14 +-
 routers/admin/users.go                        |   6 +-
 routers/admin/users_test.go                   |   8 +-
 routers/api/v1/api.go                         |   4 +-
 routers/api/v1/repo/migrate.go                |   4 +-
 routers/api/v1/repo/pull.go                   |   4 +-
 routers/api/v1/swagger/options.go             |   6 +-
 routers/install.go                            |   6 +-
 routers/org/org.go                            |   4 +-
 routers/org/org_labels.go                     |   8 +-
 routers/org/setting.go                        |   8 +-
 routers/org/teams.go                          |   6 +-
 routers/repo/branch.go                        |   4 +-
 routers/repo/editor.go                        |  16 +-
 routers/repo/issue.go                         |  12 +-
 routers/repo/issue_label.go                   |   8 +-
 routers/repo/issue_label_test.go              |   8 +-
 routers/repo/issue_lock.go                    |   4 +-
 routers/repo/issue_timetrack.go               |   2 +-
 routers/repo/migrate.go                       |  10 +-
 routers/repo/milestone.go                     |   6 +-
 routers/repo/projects.go                      |  12 +-
 routers/repo/pull.go                          |   8 +-
 routers/repo/pull_review.go                   |   8 +-
 routers/repo/release.go                       |   6 +-
 routers/repo/release_test.go                  |   8 +-
 routers/repo/repo.go                          |   4 +-
 routers/repo/setting.go                       |  14 +-
 routers/repo/setting_protected_branch.go      |   4 +-
 routers/repo/settings_test.go                 |   6 +-
 routers/repo/webhook.go                       |  42 +--
 routers/repo/wiki.go                          |   6 +-
 routers/repo/wiki_test.go                     |   8 +-
 routers/routes/install.go                     |   2 +-
 routers/routes/web.go                         | 268 +++++++++---------
 routers/user/auth.go                          |  20 +-
 routers/user/auth_openid.go                   |  20 +-
 routers/user/oauth.go                         |  12 +-
 routers/user/setting/account.go               |   8 +-
 routers/user/setting/account_test.go          |   4 +-
 routers/user/setting/applications.go          |   4 +-
 routers/user/setting/keys.go                  |   4 +-
 routers/user/setting/oauth2.go                |   6 +-
 routers/user/setting/profile.go               |  10 +-
 routers/user/setting/security_openid.go       |   8 +-
 routers/user/setting/security_twofa.go        |   4 +-
 routers/user/setting/security_u2f.go          |   6 +-
 {modules => services}/forms/admin.go          |   0
 {modules => services}/forms/auth_form.go      |   0
 {modules => services}/forms/org.go            |   0
 .../forms/repo_branch_form.go                 |   0
 {modules => services}/forms/repo_form.go      |   0
 {modules => services}/forms/repo_form_test.go |   0
 {modules => services}/forms/user_form.go      |   0
 .../forms/user_form_auth_openid.go            |   0
 {modules => services}/forms/user_form_test.go |   0
 templates/swagger/v1_json.tmpl                |   4 +-
 60 files changed, 335 insertions(+), 335 deletions(-)
 rename {modules => services}/forms/admin.go (100%)
 rename {modules => services}/forms/auth_form.go (100%)
 rename {modules => services}/forms/org.go (100%)
 rename {modules => services}/forms/repo_branch_form.go (100%)
 rename {modules => services}/forms/repo_form.go (100%)
 rename {modules => services}/forms/repo_form_test.go (100%)
 rename {modules => services}/forms/user_form.go (100%)
 rename {modules => services}/forms/user_form_auth_openid.go (100%)
 rename {modules => services}/forms/user_form_test.go (100%)

diff --git a/integrations/api_helper_for_declarative_test.go b/integrations/api_helper_for_declarative_test.go
index 913fce1577..9399924b5e 100644
--- a/integrations/api_helper_for_declarative_test.go
+++ b/integrations/api_helper_for_declarative_test.go
@@ -14,9 +14,9 @@ import (
 	"time"
 
 	"code.gitea.io/gitea/models"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/queue"
 	api "code.gitea.io/gitea/modules/structs"
+	"code.gitea.io/gitea/services/forms"
 
 	jsoniter "github.com/json-iterator/go"
 	"github.com/stretchr/testify/assert"
@@ -243,7 +243,7 @@ func doAPIMergePullRequest(ctx APITestContext, owner, repo string, index int64)
 	return func(t *testing.T) {
 		urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/merge?token=%s",
 			owner, repo, index, ctx.Token)
-		req := NewRequestWithJSON(t, http.MethodPost, urlStr, &auth.MergePullRequestForm{
+		req := NewRequestWithJSON(t, http.MethodPost, urlStr, &forms.MergePullRequestForm{
 			MergeMessageField: "doAPIMergePullRequest Merge",
 			Do:                string(models.MergeStyleMerge),
 		})
@@ -255,7 +255,7 @@ func doAPIMergePullRequest(ctx APITestContext, owner, repo string, index int64)
 			DecodeJSON(t, resp, &err)
 			assert.EqualValues(t, "Please try again later", err.Message)
 			queue.GetManager().FlushAll(context.Background(), 5*time.Second)
-			req = NewRequestWithJSON(t, http.MethodPost, urlStr, &auth.MergePullRequestForm{
+			req = NewRequestWithJSON(t, http.MethodPost, urlStr, &forms.MergePullRequestForm{
 				MergeMessageField: "doAPIMergePullRequest Merge",
 				Do:                string(models.MergeStyleMerge),
 			})
@@ -278,7 +278,7 @@ func doAPIManuallyMergePullRequest(ctx APITestContext, owner, repo, commitID str
 	return func(t *testing.T) {
 		urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/merge?token=%s",
 			owner, repo, index, ctx.Token)
-		req := NewRequestWithJSON(t, http.MethodPost, urlStr, &auth.MergePullRequestForm{
+		req := NewRequestWithJSON(t, http.MethodPost, urlStr, &forms.MergePullRequestForm{
 			Do:            string(models.MergeStyleManuallyMerged),
 			MergeCommitID: commitID,
 		})
diff --git a/integrations/api_pull_test.go b/integrations/api_pull_test.go
index 7aa0bfc54c..e6a4aca153 100644
--- a/integrations/api_pull_test.go
+++ b/integrations/api_pull_test.go
@@ -10,9 +10,9 @@ import (
 	"testing"
 
 	"code.gitea.io/gitea/models"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/setting"
 	api "code.gitea.io/gitea/modules/structs"
+	"code.gitea.io/gitea/services/forms"
 	issue_service "code.gitea.io/gitea/services/issue"
 
 	"github.com/stretchr/testify/assert"
@@ -50,7 +50,7 @@ func TestAPIMergePullWIP(t *testing.T) {
 
 	session := loginUser(t, owner.Name)
 	token := getTokenForLoggedInUser(t, session)
-	req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/merge?token=%s", owner.Name, repo.Name, pr.Index, token), &auth.MergePullRequestForm{
+	req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/merge?token=%s", owner.Name, repo.Name, pr.Index, token), &forms.MergePullRequestForm{
 		MergeMessageField: pr.Issue.Title,
 		Do:                string(models.MergeStyleMerge),
 	})
diff --git a/routers/admin/admin.go b/routers/admin/admin.go
index 0ce3dfc05f..c2d94ab9c9 100644
--- a/routers/admin/admin.go
+++ b/routers/admin/admin.go
@@ -19,7 +19,6 @@ import (
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/cron"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/process"
@@ -27,6 +26,7 @@ import (
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/timeutil"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 	"code.gitea.io/gitea/services/mailer"
 	jsoniter "github.com/json-iterator/go"
 
@@ -134,7 +134,7 @@ func Dashboard(ctx *context.Context) {
 
 // DashboardPost run an admin operation
 func DashboardPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.AdminDashboardForm)
+	form := web.GetForm(ctx).(*forms.AdminDashboardForm)
 	ctx.Data["Title"] = ctx.Tr("admin.dashboard")
 	ctx.Data["PageIsAdmin"] = true
 	ctx.Data["PageIsAdminDashboard"] = true
diff --git a/routers/admin/auths.go b/routers/admin/auths.go
index 790eecedb7..a0a20fa023 100644
--- a/routers/admin/auths.go
+++ b/routers/admin/auths.go
@@ -16,11 +16,11 @@ import (
 	"code.gitea.io/gitea/modules/auth/pam"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/util"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 
 	"xorm.io/xorm/convert"
 )
@@ -113,7 +113,7 @@ func NewAuthSource(ctx *context.Context) {
 	ctx.HTML(http.StatusOK, tplAuthNew)
 }
 
-func parseLDAPConfig(form auth.AuthenticationForm) *models.LDAPConfig {
+func parseLDAPConfig(form forms.AuthenticationForm) *models.LDAPConfig {
 	var pageSize uint32
 	if form.UsePagedSearch {
 		pageSize = uint32(form.SearchPageSize)
@@ -150,7 +150,7 @@ func parseLDAPConfig(form auth.AuthenticationForm) *models.LDAPConfig {
 	}
 }
 
-func parseSMTPConfig(form auth.AuthenticationForm) *models.SMTPConfig {
+func parseSMTPConfig(form forms.AuthenticationForm) *models.SMTPConfig {
 	return &models.SMTPConfig{
 		Auth:           form.SMTPAuth,
 		Host:           form.SMTPHost,
@@ -161,7 +161,7 @@ func parseSMTPConfig(form auth.AuthenticationForm) *models.SMTPConfig {
 	}
 }
 
-func parseOAuth2Config(form auth.AuthenticationForm) *models.OAuth2Config {
+func parseOAuth2Config(form forms.AuthenticationForm) *models.OAuth2Config {
 	var customURLMapping *oauth2.CustomURLMapping
 	if form.Oauth2UseCustomURL {
 		customURLMapping = &oauth2.CustomURLMapping{
@@ -183,7 +183,7 @@ func parseOAuth2Config(form auth.AuthenticationForm) *models.OAuth2Config {
 	}
 }
 
-func parseSSPIConfig(ctx *context.Context, form auth.AuthenticationForm) (*models.SSPIConfig, error) {
+func parseSSPIConfig(ctx *context.Context, form forms.AuthenticationForm) (*models.SSPIConfig, error) {
 	if util.IsEmptyString(form.SSPISeparatorReplacement) {
 		ctx.Data["Err_SSPISeparatorReplacement"] = true
 		return nil, errors.New(ctx.Tr("form.SSPISeparatorReplacement") + ctx.Tr("form.require_error"))
@@ -209,7 +209,7 @@ func parseSSPIConfig(ctx *context.Context, form auth.AuthenticationForm) (*model
 
 // NewAuthSourcePost response for adding an auth source
 func NewAuthSourcePost(ctx *context.Context) {
-	form := *web.GetForm(ctx).(*auth.AuthenticationForm)
+	form := *web.GetForm(ctx).(*forms.AuthenticationForm)
 	ctx.Data["Title"] = ctx.Tr("admin.auths.new")
 	ctx.Data["PageIsAdmin"] = true
 	ctx.Data["PageIsAdminAuthentications"] = true
@@ -316,7 +316,7 @@ func EditAuthSource(ctx *context.Context) {
 
 // EditAuthSourcePost response for editing auth source
 func EditAuthSourcePost(ctx *context.Context) {
-	form := *web.GetForm(ctx).(*auth.AuthenticationForm)
+	form := *web.GetForm(ctx).(*forms.AuthenticationForm)
 	ctx.Data["Title"] = ctx.Tr("admin.auths.edit")
 	ctx.Data["PageIsAdmin"] = true
 	ctx.Data["PageIsAdminAuthentications"] = true
diff --git a/routers/admin/users.go b/routers/admin/users.go
index 13609ac746..3b29eeefc1 100644
--- a/routers/admin/users.go
+++ b/routers/admin/users.go
@@ -14,13 +14,13 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/password"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/web"
 	"code.gitea.io/gitea/routers"
 	router_user_setting "code.gitea.io/gitea/routers/user/setting"
+	"code.gitea.io/gitea/services/forms"
 	"code.gitea.io/gitea/services/mailer"
 )
 
@@ -66,7 +66,7 @@ func NewUser(ctx *context.Context) {
 
 // NewUserPost response for adding a new user
 func NewUserPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.AdminCreateUserForm)
+	form := web.GetForm(ctx).(*forms.AdminCreateUserForm)
 	ctx.Data["Title"] = ctx.Tr("admin.users.new_account")
 	ctx.Data["PageIsAdmin"] = true
 	ctx.Data["PageIsAdminUsers"] = true
@@ -218,7 +218,7 @@ func EditUser(ctx *context.Context) {
 
 // EditUserPost response for editting user
 func EditUserPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.AdminEditUserForm)
+	form := web.GetForm(ctx).(*forms.AdminEditUserForm)
 	ctx.Data["Title"] = ctx.Tr("admin.users.edit_account")
 	ctx.Data["PageIsAdmin"] = true
 	ctx.Data["PageIsAdminUsers"] = true
diff --git a/routers/admin/users_test.go b/routers/admin/users_test.go
index bd00bb2bf1..b19dcb886b 100644
--- a/routers/admin/users_test.go
+++ b/routers/admin/users_test.go
@@ -8,9 +8,9 @@ import (
 	"testing"
 
 	"code.gitea.io/gitea/models"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/test"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 
 	"github.com/stretchr/testify/assert"
 )
@@ -30,7 +30,7 @@ func TestNewUserPost_MustChangePassword(t *testing.T) {
 	username := "gitea"
 	email := "gitea@gitea.io"
 
-	form := auth.AdminCreateUserForm{
+	form := forms.AdminCreateUserForm{
 		LoginType:          "local",
 		LoginName:          "local",
 		UserName:           username,
@@ -68,7 +68,7 @@ func TestNewUserPost_MustChangePasswordFalse(t *testing.T) {
 	username := "gitea"
 	email := "gitea@gitea.io"
 
-	form := auth.AdminCreateUserForm{
+	form := forms.AdminCreateUserForm{
 		LoginType:          "local",
 		LoginName:          "local",
 		UserName:           username,
@@ -106,7 +106,7 @@ func TestNewUserPost_InvalidEmail(t *testing.T) {
 	username := "gitea"
 	email := "gitea@gitea.io\r\n"
 
-	form := auth.AdminCreateUserForm{
+	form := forms.AdminCreateUserForm{
 		LoginType:          "local",
 		LoginName:          "local",
 		UserName:           username,
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go
index 88355fb2b3..ecb3a3f03d 100644
--- a/routers/api/v1/api.go
+++ b/routers/api/v1/api.go
@@ -71,7 +71,6 @@ import (
 
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/setting"
 	api "code.gitea.io/gitea/modules/structs"
@@ -84,6 +83,7 @@ import (
 	"code.gitea.io/gitea/routers/api/v1/settings"
 	_ "code.gitea.io/gitea/routers/api/v1/swagger" // for swagger generation
 	"code.gitea.io/gitea/routers/api/v1/user"
+	"code.gitea.io/gitea/services/forms"
 
 	"gitea.com/go-chi/binding"
 	"gitea.com/go-chi/session"
@@ -897,7 +897,7 @@ func Routes() *web.Route {
 						m.Get(".patch", repo.DownloadPullPatch)
 						m.Post("/update", reqToken(), repo.UpdatePullRequest)
 						m.Combo("/merge").Get(repo.IsPullRequestMerged).
-							Post(reqToken(), mustNotBeArchived, bind(auth.MergePullRequestForm{}), repo.MergePullRequest)
+							Post(reqToken(), mustNotBeArchived, bind(forms.MergePullRequestForm{}), repo.MergePullRequest)
 						m.Group("/reviews", func() {
 							m.Combo("").
 								Get(repo.ListPullReviews).
diff --git a/routers/api/v1/repo/migrate.go b/routers/api/v1/repo/migrate.go
index 1eefa78d57..1c36e0cc79 100644
--- a/routers/api/v1/repo/migrate.go
+++ b/routers/api/v1/repo/migrate.go
@@ -14,7 +14,6 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/convert"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/graceful"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/migrations"
@@ -25,6 +24,7 @@ import (
 	api "code.gitea.io/gitea/modules/structs"
 	"code.gitea.io/gitea/modules/util"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 )
 
 // Migrate migrate remote git repository to gitea
@@ -96,7 +96,7 @@ func Migrate(ctx *context.APIContext) {
 		}
 	}
 
-	remoteAddr, err := auth.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword)
+	remoteAddr, err := forms.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword)
 	if err == nil {
 		err = migrations.IsMigrateURLAllowed(remoteAddr, ctx.User)
 	}
diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go
index e3be5b4af4..2d16e801db 100644
--- a/routers/api/v1/repo/pull.go
+++ b/routers/api/v1/repo/pull.go
@@ -13,7 +13,6 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/convert"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/notification"
@@ -21,6 +20,7 @@ import (
 	"code.gitea.io/gitea/modules/timeutil"
 	"code.gitea.io/gitea/modules/web"
 	"code.gitea.io/gitea/routers/api/v1/utils"
+	"code.gitea.io/gitea/services/forms"
 	issue_service "code.gitea.io/gitea/services/issue"
 	pull_service "code.gitea.io/gitea/services/pull"
 )
@@ -721,7 +721,7 @@ func MergePullRequest(ctx *context.APIContext) {
 	//   "409":
 	//     "$ref": "#/responses/error"
 
-	form := web.GetForm(ctx).(*auth.MergePullRequestForm)
+	form := web.GetForm(ctx).(*forms.MergePullRequestForm)
 	pr, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
 	if err != nil {
 		if models.IsErrPullRequestNotExist(err) {
diff --git a/routers/api/v1/swagger/options.go b/routers/api/v1/swagger/options.go
index a2dc2193a8..dad025710d 100644
--- a/routers/api/v1/swagger/options.go
+++ b/routers/api/v1/swagger/options.go
@@ -5,8 +5,8 @@
 package swagger
 
 import (
-	auth "code.gitea.io/gitea/modules/forms"
 	api "code.gitea.io/gitea/modules/structs"
+	"code.gitea.io/gitea/services/forms"
 )
 
 // not actually a response, just a hack to get go-swagger to include definitions
@@ -72,7 +72,7 @@ type swaggerParameterBodies struct {
 	// in:body
 	EditPullRequestOption api.EditPullRequestOption
 	// in:body
-	MergePullRequestOption auth.MergePullRequestForm
+	MergePullRequestOption forms.MergePullRequestForm
 
 	// in:body
 	CreateReleaseOption api.CreateReleaseOption
@@ -106,7 +106,7 @@ type swaggerParameterBodies struct {
 	EditUserOption api.EditUserOption
 
 	// in:body
-	MigrateRepoForm auth.MigrateRepoForm
+	MigrateRepoForm forms.MigrateRepoForm
 
 	// in:body
 	EditAttachmentOptions api.EditAttachmentOptions
diff --git a/routers/install.go b/routers/install.go
index 86ec761e7c..ef53422c4e 100644
--- a/routers/install.go
+++ b/routers/install.go
@@ -16,7 +16,6 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/generate"
 	"code.gitea.io/gitea/modules/graceful"
 	"code.gitea.io/gitea/modules/log"
@@ -26,6 +25,7 @@ import (
 	"code.gitea.io/gitea/modules/util"
 	"code.gitea.io/gitea/modules/web"
 	"code.gitea.io/gitea/modules/web/middleware"
+	"code.gitea.io/gitea/services/forms"
 
 	"gitea.com/go-chi/session"
 	"gopkg.in/ini.v1"
@@ -76,7 +76,7 @@ func InstallInit(next http.Handler) http.Handler {
 
 // Install render installation page
 func Install(ctx *context.Context) {
-	form := auth.InstallForm{}
+	form := forms.InstallForm{}
 
 	// Database settings
 	form.DbHost = setting.Database.Host
@@ -151,7 +151,7 @@ func Install(ctx *context.Context) {
 
 // InstallPost response for submit install items
 func InstallPost(ctx *context.Context) {
-	form := *web.GetForm(ctx).(*auth.InstallForm)
+	form := *web.GetForm(ctx).(*forms.InstallForm)
 	var err error
 	ctx.Data["CurDbOption"] = form.DbType
 
diff --git a/routers/org/org.go b/routers/org/org.go
index 7b430e1708..ef96987d42 100644
--- a/routers/org/org.go
+++ b/routers/org/org.go
@@ -12,10 +12,10 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 )
 
 const (
@@ -36,7 +36,7 @@ func Create(ctx *context.Context) {
 
 // CreatePost response for create organization
 func CreatePost(ctx *context.Context) {
-	form := *web.GetForm(ctx).(*auth.CreateOrgForm)
+	form := *web.GetForm(ctx).(*forms.CreateOrgForm)
 	ctx.Data["Title"] = ctx.Tr("new_org")
 
 	if !ctx.User.CanCreateOrganization() {
diff --git a/routers/org/org_labels.go b/routers/org/org_labels.go
index a21976402c..26e232bcc9 100644
--- a/routers/org/org_labels.go
+++ b/routers/org/org_labels.go
@@ -9,8 +9,8 @@ import (
 
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 )
 
 // RetrieveLabels find all the labels of an organization
@@ -30,7 +30,7 @@ func RetrieveLabels(ctx *context.Context) {
 
 // NewLabel create new label for organization
 func NewLabel(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.CreateLabelForm)
+	form := web.GetForm(ctx).(*forms.CreateLabelForm)
 	ctx.Data["Title"] = ctx.Tr("repo.labels")
 	ctx.Data["PageIsLabels"] = true
 
@@ -55,7 +55,7 @@ func NewLabel(ctx *context.Context) {
 
 // UpdateLabel update a label's name and color
 func UpdateLabel(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.CreateLabelForm)
+	form := web.GetForm(ctx).(*forms.CreateLabelForm)
 	l, err := models.GetLabelInOrgByID(ctx.Org.Organization.ID, form.ID)
 	if err != nil {
 		switch {
@@ -92,7 +92,7 @@ func DeleteLabel(ctx *context.Context) {
 
 // InitializeLabels init labels for an organization
 func InitializeLabels(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.InitializeLabelsForm)
+	form := web.GetForm(ctx).(*forms.InitializeLabelsForm)
 	if ctx.HasError() {
 		ctx.Redirect(ctx.Repo.RepoLink + "/labels")
 		return
diff --git a/routers/org/setting.go b/routers/org/setting.go
index aac8fefcc2..e7995fe8fa 100644
--- a/routers/org/setting.go
+++ b/routers/org/setting.go
@@ -12,11 +12,11 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/web"
 	userSetting "code.gitea.io/gitea/routers/user/setting"
+	"code.gitea.io/gitea/services/forms"
 )
 
 const (
@@ -41,7 +41,7 @@ func Settings(ctx *context.Context) {
 
 // SettingsPost response for settings change submited
 func SettingsPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.UpdateOrgSettingForm)
+	form := web.GetForm(ctx).(*forms.UpdateOrgSettingForm)
 	ctx.Data["Title"] = ctx.Tr("org.settings")
 	ctx.Data["PageIsSettingsOptions"] = true
 	ctx.Data["CurrentVisibility"] = ctx.Org.Organization.Visibility
@@ -119,8 +119,8 @@ func SettingsPost(ctx *context.Context) {
 
 // SettingsAvatar response for change avatar on settings page
 func SettingsAvatar(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.AvatarForm)
-	form.Source = auth.AvatarLocal
+	form := web.GetForm(ctx).(*forms.AvatarForm)
+	form.Source = forms.AvatarLocal
 	if err := userSetting.UpdateAvatarSetting(ctx, form, ctx.Org.Organization); err != nil {
 		ctx.Flash.Error(err.Error())
 	} else {
diff --git a/routers/org/teams.go b/routers/org/teams.go
index ad2c869eb6..520ded33b4 100644
--- a/routers/org/teams.go
+++ b/routers/org/teams.go
@@ -13,10 +13,10 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/web"
 	"code.gitea.io/gitea/routers/utils"
+	"code.gitea.io/gitea/services/forms"
 )
 
 const (
@@ -188,7 +188,7 @@ func NewTeam(ctx *context.Context) {
 
 // NewTeamPost response for create new team
 func NewTeamPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.CreateTeamForm)
+	form := web.GetForm(ctx).(*forms.CreateTeamForm)
 	ctx.Data["Title"] = ctx.Org.Organization.FullName
 	ctx.Data["PageIsOrgTeams"] = true
 	ctx.Data["PageIsOrgTeamsNew"] = true
@@ -277,7 +277,7 @@ func EditTeam(ctx *context.Context) {
 
 // EditTeamPost response for modify team information
 func EditTeamPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.CreateTeamForm)
+	form := web.GetForm(ctx).(*forms.CreateTeamForm)
 	t := ctx.Org.Team
 	ctx.Data["Title"] = ctx.Org.Organization.FullName
 	ctx.Data["PageIsOrgTeams"] = true
diff --git a/routers/repo/branch.go b/routers/repo/branch.go
index 9a47a41063..eecaa88821 100644
--- a/routers/repo/branch.go
+++ b/routers/repo/branch.go
@@ -13,7 +13,6 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/repofiles"
@@ -21,6 +20,7 @@ import (
 	"code.gitea.io/gitea/modules/util"
 	"code.gitea.io/gitea/modules/web"
 	"code.gitea.io/gitea/routers/utils"
+	"code.gitea.io/gitea/services/forms"
 	release_service "code.gitea.io/gitea/services/release"
 	repo_service "code.gitea.io/gitea/services/repository"
 )
@@ -372,7 +372,7 @@ func getDeletedBranches(ctx *context.Context) ([]*Branch, error) {
 
 // CreateBranch creates new branch in repository
 func CreateBranch(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.NewBranchForm)
+	form := web.GetForm(ctx).(*forms.NewBranchForm)
 	if !ctx.Repo.CanCreateBranch() {
 		ctx.NotFound("CreateBranch", nil)
 		return
diff --git a/routers/repo/editor.go b/routers/repo/editor.go
index 3155eca627..2cc5c1e7f2 100644
--- a/routers/repo/editor.go
+++ b/routers/repo/editor.go
@@ -15,7 +15,6 @@ import (
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/charset"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/repofiles"
@@ -25,6 +24,7 @@ import (
 	"code.gitea.io/gitea/modules/util"
 	"code.gitea.io/gitea/modules/web"
 	"code.gitea.io/gitea/routers/utils"
+	"code.gitea.io/gitea/services/forms"
 	jsoniter "github.com/json-iterator/go"
 )
 
@@ -177,7 +177,7 @@ func NewFile(ctx *context.Context) {
 	editFile(ctx, true)
 }
 
-func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bool) {
+func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile bool) {
 	canCommit := renderCommitRights(ctx)
 	treeNames, treePaths := getParentTreeFields(form.TreePath)
 	branchName := ctx.Repo.BranchName
@@ -330,19 +330,19 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo
 
 // EditFilePost response for editing file
 func EditFilePost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.EditRepoFileForm)
+	form := web.GetForm(ctx).(*forms.EditRepoFileForm)
 	editFilePost(ctx, *form, false)
 }
 
 // NewFilePost response for creating file
 func NewFilePost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.EditRepoFileForm)
+	form := web.GetForm(ctx).(*forms.EditRepoFileForm)
 	editFilePost(ctx, *form, true)
 }
 
 // DiffPreviewPost render preview diff page
 func DiffPreviewPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.EditPreviewDiffForm)
+	form := web.GetForm(ctx).(*forms.EditPreviewDiffForm)
 	treePath := cleanUploadFileName(ctx.Repo.TreePath)
 	if len(treePath) == 0 {
 		ctx.Error(http.StatusInternalServerError, "file name to diff is invalid")
@@ -402,7 +402,7 @@ func DeleteFile(ctx *context.Context) {
 
 // DeleteFilePost response for deleting file
 func DeleteFilePost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.DeleteRepoFileForm)
+	form := web.GetForm(ctx).(*forms.DeleteRepoFileForm)
 	canCommit := renderCommitRights(ctx)
 	branchName := ctx.Repo.BranchName
 	if form.CommitChoice == frmCommitChoiceNewBranch {
@@ -566,7 +566,7 @@ func UploadFile(ctx *context.Context) {
 
 // UploadFilePost response for uploading file
 func UploadFilePost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.UploadRepoFileForm)
+	form := web.GetForm(ctx).(*forms.UploadRepoFileForm)
 	ctx.Data["PageIsUpload"] = true
 	ctx.Data["RequireTribute"] = true
 	ctx.Data["RequireSimpleMDE"] = true
@@ -772,7 +772,7 @@ func UploadFileToServer(ctx *context.Context) {
 
 // RemoveUploadFileFromServer remove file from server file dir
 func RemoveUploadFileFromServer(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.RemoveUploadFileForm)
+	form := web.GetForm(ctx).(*forms.RemoveUploadFileForm)
 	if len(form.File) == 0 {
 		ctx.Status(204)
 		return
diff --git a/routers/repo/issue.go b/routers/repo/issue.go
index 73531fc313..4475e35f63 100644
--- a/routers/repo/issue.go
+++ b/routers/repo/issue.go
@@ -19,7 +19,6 @@ import (
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/convert"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/git"
 	issue_indexer "code.gitea.io/gitea/modules/indexer/issues"
 	"code.gitea.io/gitea/modules/log"
@@ -31,6 +30,7 @@ import (
 	"code.gitea.io/gitea/modules/util"
 	"code.gitea.io/gitea/modules/web"
 	comment_service "code.gitea.io/gitea/services/comments"
+	"code.gitea.io/gitea/services/forms"
 	issue_service "code.gitea.io/gitea/services/issue"
 	pull_service "code.gitea.io/gitea/services/pull"
 
@@ -836,7 +836,7 @@ func NewIssueChooseTemplate(ctx *context.Context) {
 }
 
 // ValidateRepoMetas check and returns repository's meta informations
-func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm, isPull bool) ([]int64, []int64, int64, int64) {
+func ValidateRepoMetas(ctx *context.Context, form forms.CreateIssueForm, isPull bool) ([]int64, []int64, int64, int64) {
 	var (
 		repo = ctx.Repo.Repository
 		err  error
@@ -934,7 +934,7 @@ func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm, isPull b
 
 // NewIssuePost response for creating new issue
 func NewIssuePost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.CreateIssueForm)
+	form := web.GetForm(ctx).(*forms.CreateIssueForm)
 	ctx.Data["Title"] = ctx.Tr("repo.issues.new")
 	ctx.Data["PageIsIssueList"] = true
 	ctx.Data["NewIssueChooseTemplate"] = len(ctx.IssueTemplatesFromDefaultBranch()) > 0
@@ -1961,7 +1961,7 @@ func UpdateIssueStatus(ctx *context.Context) {
 
 // NewComment create a comment for issue
 func NewComment(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.CreateCommentForm)
+	form := web.GetForm(ctx).(*forms.CreateCommentForm)
 	issue := GetActionIssue(ctx)
 	if ctx.Written() {
 		return
@@ -2171,7 +2171,7 @@ func DeleteComment(ctx *context.Context) {
 
 // ChangeIssueReaction create a reaction for issue
 func ChangeIssueReaction(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.ReactionForm)
+	form := web.GetForm(ctx).(*forms.ReactionForm)
 	issue := GetActionIssue(ctx)
 	if ctx.Written() {
 		return
@@ -2267,7 +2267,7 @@ func ChangeIssueReaction(ctx *context.Context) {
 
 // ChangeCommentReaction create a reaction for comment
 func ChangeCommentReaction(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.ReactionForm)
+	form := web.GetForm(ctx).(*forms.ReactionForm)
 	comment, err := models.GetCommentByID(ctx.ParamsInt64(":id"))
 	if err != nil {
 		ctx.NotFoundOrServerError("GetCommentByID", models.IsErrCommentNotExist, err)
diff --git a/routers/repo/issue_label.go b/routers/repo/issue_label.go
index 28df82a2d5..6f862b6d0d 100644
--- a/routers/repo/issue_label.go
+++ b/routers/repo/issue_label.go
@@ -10,10 +10,10 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 	issue_service "code.gitea.io/gitea/services/issue"
 )
 
@@ -33,7 +33,7 @@ func Labels(ctx *context.Context) {
 
 // InitializeLabels init labels for a repository
 func InitializeLabels(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.InitializeLabelsForm)
+	form := web.GetForm(ctx).(*forms.InitializeLabelsForm)
 	if ctx.HasError() {
 		ctx.Redirect(ctx.Repo.RepoLink + "/labels")
 		return
@@ -99,7 +99,7 @@ func RetrieveLabels(ctx *context.Context) {
 
 // NewLabel create new label for repository
 func NewLabel(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.CreateLabelForm)
+	form := web.GetForm(ctx).(*forms.CreateLabelForm)
 	ctx.Data["Title"] = ctx.Tr("repo.labels")
 	ctx.Data["PageIsLabels"] = true
 
@@ -124,7 +124,7 @@ func NewLabel(ctx *context.Context) {
 
 // UpdateLabel update a label's name and color
 func UpdateLabel(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.CreateLabelForm)
+	form := web.GetForm(ctx).(*forms.CreateLabelForm)
 	l, err := models.GetLabelInRepoByID(ctx.Repo.Repository.ID, form.ID)
 	if err != nil {
 		switch {
diff --git a/routers/repo/issue_label_test.go b/routers/repo/issue_label_test.go
index d67c70085d..bf9e72a6f4 100644
--- a/routers/repo/issue_label_test.go
+++ b/routers/repo/issue_label_test.go
@@ -10,9 +10,9 @@ import (
 	"testing"
 
 	"code.gitea.io/gitea/models"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/test"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 
 	"github.com/stretchr/testify/assert"
 )
@@ -33,7 +33,7 @@ func TestInitializeLabels(t *testing.T) {
 	ctx := test.MockContext(t, "user2/repo1/labels/initialize")
 	test.LoadUser(t, ctx, 2)
 	test.LoadRepo(t, ctx, 2)
-	web.SetForm(ctx, &auth.InitializeLabelsForm{TemplateName: "Default"})
+	web.SetForm(ctx, &forms.InitializeLabelsForm{TemplateName: "Default"})
 	InitializeLabels(ctx)
 	assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
 	models.AssertExistsAndLoadBean(t, &models.Label{
@@ -76,7 +76,7 @@ func TestNewLabel(t *testing.T) {
 	ctx := test.MockContext(t, "user2/repo1/labels/edit")
 	test.LoadUser(t, ctx, 2)
 	test.LoadRepo(t, ctx, 1)
-	web.SetForm(ctx, &auth.CreateLabelForm{
+	web.SetForm(ctx, &forms.CreateLabelForm{
 		Title: "newlabel",
 		Color: "#abcdef",
 	})
@@ -94,7 +94,7 @@ func TestUpdateLabel(t *testing.T) {
 	ctx := test.MockContext(t, "user2/repo1/labels/edit")
 	test.LoadUser(t, ctx, 2)
 	test.LoadRepo(t, ctx, 1)
-	web.SetForm(ctx, &auth.CreateLabelForm{
+	web.SetForm(ctx, &forms.CreateLabelForm{
 		ID:    2,
 		Title: "newnameforlabel",
 		Color: "#abcdef",
diff --git a/routers/repo/issue_lock.go b/routers/repo/issue_lock.go
index f8131e46aa..36894b4be3 100644
--- a/routers/repo/issue_lock.go
+++ b/routers/repo/issue_lock.go
@@ -9,14 +9,14 @@ import (
 
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 )
 
 // LockIssue locks an issue. This would limit commenting abilities to
 // users with write access to the repo.
 func LockIssue(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.IssueLockForm)
+	form := web.GetForm(ctx).(*forms.IssueLockForm)
 	issue := GetActionIssue(ctx)
 	if ctx.Written() {
 		return
diff --git a/routers/repo/issue_timetrack.go b/routers/repo/issue_timetrack.go
index 3b13770d61..3770cd7b4e 100644
--- a/routers/repo/issue_timetrack.go
+++ b/routers/repo/issue_timetrack.go
@@ -10,8 +10,8 @@ import (
 
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/context"
-	"code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 )
 
 // AddTimeManually tracks time manually
diff --git a/routers/repo/migrate.go b/routers/repo/migrate.go
index 752cdbf512..8da37b5ec9 100644
--- a/routers/repo/migrate.go
+++ b/routers/repo/migrate.go
@@ -12,7 +12,6 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/migrations"
 	"code.gitea.io/gitea/modules/setting"
@@ -20,6 +19,7 @@ import (
 	"code.gitea.io/gitea/modules/task"
 	"code.gitea.io/gitea/modules/util"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 )
 
 const (
@@ -63,7 +63,7 @@ func Migrate(ctx *context.Context) {
 	ctx.HTML(http.StatusOK, base.TplName("repo/migrate/"+serviceType.Name()))
 }
 
-func handleMigrateError(ctx *context.Context, owner *models.User, err error, name string, tpl base.TplName, form *auth.MigrateRepoForm) {
+func handleMigrateError(ctx *context.Context, owner *models.User, err error, name string, tpl base.TplName, form *forms.MigrateRepoForm) {
 	if setting.Repository.DisableMigrations {
 		ctx.Error(http.StatusForbidden, "MigrateError: the site administrator has disabled migrations")
 		return
@@ -98,7 +98,7 @@ func handleMigrateError(ctx *context.Context, owner *models.User, err error, nam
 		ctx.Data["Err_RepoName"] = true
 		ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), tpl, form)
 	default:
-		remoteAddr, _ := auth.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword)
+		remoteAddr, _ := forms.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword)
 		err = util.URLSanitizedError(err, remoteAddr)
 		if strings.Contains(err.Error(), "Authentication failed") ||
 			strings.Contains(err.Error(), "Bad credentials") ||
@@ -116,7 +116,7 @@ func handleMigrateError(ctx *context.Context, owner *models.User, err error, nam
 
 // MigratePost response for migrating from external git repository
 func MigratePost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.MigrateRepoForm)
+	form := web.GetForm(ctx).(*forms.MigrateRepoForm)
 	if setting.Repository.DisableMigrations {
 		ctx.Error(http.StatusForbidden, "MigratePost: the site administrator has disabled migrations")
 		return
@@ -139,7 +139,7 @@ func MigratePost(ctx *context.Context) {
 		return
 	}
 
-	remoteAddr, err := auth.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword)
+	remoteAddr, err := forms.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword)
 	if err == nil {
 		err = migrations.IsMigrateURLAllowed(remoteAddr, ctx.User)
 	}
diff --git a/routers/repo/milestone.go b/routers/repo/milestone.go
index 2dc8366f0d..4d1fc022c2 100644
--- a/routers/repo/milestone.go
+++ b/routers/repo/milestone.go
@@ -11,13 +11,13 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/markup/markdown"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/structs"
 	"code.gitea.io/gitea/modules/timeutil"
 	"code.gitea.io/gitea/modules/util"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 
 	"xorm.io/builder"
 )
@@ -109,7 +109,7 @@ func NewMilestone(ctx *context.Context) {
 
 // NewMilestonePost response for creating milestone
 func NewMilestonePost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.CreateMilestoneForm)
+	form := web.GetForm(ctx).(*forms.CreateMilestoneForm)
 	ctx.Data["Title"] = ctx.Tr("repo.milestones.new")
 	ctx.Data["PageIsIssueList"] = true
 	ctx.Data["PageIsMilestones"] = true
@@ -169,7 +169,7 @@ func EditMilestone(ctx *context.Context) {
 
 // EditMilestonePost response for edting milestone
 func EditMilestonePost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.CreateMilestoneForm)
+	form := web.GetForm(ctx).(*forms.CreateMilestoneForm)
 	ctx.Data["Title"] = ctx.Tr("repo.milestones.edit")
 	ctx.Data["PageIsMilestones"] = true
 	ctx.Data["PageIsEditMilestone"] = true
diff --git a/routers/repo/projects.go b/routers/repo/projects.go
index df02209876..96ef2c6c0c 100644
--- a/routers/repo/projects.go
+++ b/routers/repo/projects.go
@@ -12,11 +12,11 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/markup/markdown"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/util"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 )
 
 const (
@@ -115,7 +115,7 @@ func NewProject(ctx *context.Context) {
 
 // NewProjectPost creates a new project
 func NewProjectPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.CreateProjectForm)
+	form := web.GetForm(ctx).(*forms.CreateProjectForm)
 	ctx.Data["Title"] = ctx.Tr("repo.projects.new")
 
 	if ctx.HasError() {
@@ -221,7 +221,7 @@ func EditProject(ctx *context.Context) {
 
 // EditProjectPost response for editing a project
 func EditProjectPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.CreateProjectForm)
+	form := web.GetForm(ctx).(*forms.CreateProjectForm)
 	ctx.Data["Title"] = ctx.Tr("repo.projects.edit")
 	ctx.Data["PageIsProjects"] = true
 	ctx.Data["PageIsEditProjects"] = true
@@ -404,7 +404,7 @@ func DeleteProjectBoard(ctx *context.Context) {
 
 // AddBoardToProjectPost allows a new board to be added to a project.
 func AddBoardToProjectPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.EditProjectBoardForm)
+	form := web.GetForm(ctx).(*forms.EditProjectBoardForm)
 	if !ctx.Repo.IsOwner() && !ctx.Repo.IsAdmin() && !ctx.Repo.CanAccess(models.AccessModeWrite, models.UnitTypeProjects) {
 		ctx.JSON(http.StatusForbidden, map[string]string{
 			"message": "Only authorized users are allowed to perform this action.",
@@ -484,7 +484,7 @@ func checkProjectBoardChangePermissions(ctx *context.Context) (*models.Project,
 
 // EditProjectBoard allows a project board's to be updated
 func EditProjectBoard(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.EditProjectBoardForm)
+	form := web.GetForm(ctx).(*forms.EditProjectBoardForm)
 	_, board := checkProjectBoardChangePermissions(ctx)
 	if ctx.Written() {
 		return
@@ -614,7 +614,7 @@ func CreateProject(ctx *context.Context) {
 }
 
 // CreateProjectPost creates an individual and/or organization project
-func CreateProjectPost(ctx *context.Context, form auth.UserCreateProjectForm) {
+func CreateProjectPost(ctx *context.Context, form forms.UserCreateProjectForm) {
 
 	user := checkContextUser(ctx, form.UID)
 	if ctx.Written() {
diff --git a/routers/repo/pull.go b/routers/repo/pull.go
index 0002263013..32d11a285b 100644
--- a/routers/repo/pull.go
+++ b/routers/repo/pull.go
@@ -18,7 +18,6 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/notification"
@@ -30,6 +29,7 @@ import (
 	"code.gitea.io/gitea/modules/web"
 	"code.gitea.io/gitea/modules/web/middleware"
 	"code.gitea.io/gitea/routers/utils"
+	"code.gitea.io/gitea/services/forms"
 	"code.gitea.io/gitea/services/gitdiff"
 	pull_service "code.gitea.io/gitea/services/pull"
 	repo_service "code.gitea.io/gitea/services/repository"
@@ -172,7 +172,7 @@ func Fork(ctx *context.Context) {
 
 // ForkPost response for forking a repository
 func ForkPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.CreateRepoForm)
+	form := web.GetForm(ctx).(*forms.CreateRepoForm)
 	ctx.Data["Title"] = ctx.Tr("new_fork")
 
 	ctxUser := checkContextUser(ctx, form.UID)
@@ -764,7 +764,7 @@ func UpdatePullRequest(ctx *context.Context) {
 
 // MergePullRequest response for merging pull request
 func MergePullRequest(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.MergePullRequestForm)
+	form := web.GetForm(ctx).(*forms.MergePullRequestForm)
 	issue := checkPullInfo(ctx)
 	if ctx.Written() {
 		return
@@ -975,7 +975,7 @@ func stopTimerIfAvailable(user *models.User, issue *models.Issue) error {
 
 // CompareAndPullRequestPost response for creating pull request
 func CompareAndPullRequestPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.CreateIssueForm)
+	form := web.GetForm(ctx).(*forms.CreateIssueForm)
 	ctx.Data["Title"] = ctx.Tr("repo.pulls.compare_changes")
 	ctx.Data["PageIsComparePull"] = true
 	ctx.Data["IsDiffCompare"] = true
diff --git a/routers/repo/pull_review.go b/routers/repo/pull_review.go
index d75135c40a..9e505c3db3 100644
--- a/routers/repo/pull_review.go
+++ b/routers/repo/pull_review.go
@@ -11,9 +11,9 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 	pull_service "code.gitea.io/gitea/services/pull"
 )
 
@@ -47,7 +47,7 @@ func RenderNewCodeCommentForm(ctx *context.Context) {
 
 // CreateCodeComment will create a code comment including an pending review if required
 func CreateCodeComment(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.CodeCommentForm)
+	form := web.GetForm(ctx).(*forms.CodeCommentForm)
 	issue := GetActionIssue(ctx)
 	if !issue.IsPull {
 		return
@@ -175,7 +175,7 @@ func renderConversation(ctx *context.Context, comment *models.Comment) {
 
 // SubmitReview creates a review out of the existing pending review or creates a new one if no pending review exist
 func SubmitReview(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.SubmitReviewForm)
+	form := web.GetForm(ctx).(*forms.SubmitReviewForm)
 	issue := GetActionIssue(ctx)
 	if !issue.IsPull {
 		return
@@ -227,7 +227,7 @@ func SubmitReview(ctx *context.Context) {
 
 // DismissReview dismissing stale review by repo admin
 func DismissReview(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.DismissReviewForm)
+	form := web.GetForm(ctx).(*forms.DismissReviewForm)
 	comm, err := pull_service.DismissReview(form.ReviewID, form.Message, ctx.User, true)
 	if err != nil {
 		ctx.ServerError("pull_service.DismissReview", err)
diff --git a/routers/repo/release.go b/routers/repo/release.go
index 9f6e502482..2ebb69b6ab 100644
--- a/routers/repo/release.go
+++ b/routers/repo/release.go
@@ -14,12 +14,12 @@ import (
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/convert"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/markup/markdown"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/upload"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 	releaseservice "code.gitea.io/gitea/services/release"
 )
 
@@ -243,7 +243,7 @@ func NewRelease(ctx *context.Context) {
 
 // NewReleasePost response for creating a release
 func NewReleasePost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.NewReleaseForm)
+	form := web.GetForm(ctx).(*forms.NewReleaseForm)
 	ctx.Data["Title"] = ctx.Tr("repo.release.new_release")
 	ctx.Data["PageIsReleaseList"] = true
 	ctx.Data["RequireSimpleMDE"] = true
@@ -384,7 +384,7 @@ func EditRelease(ctx *context.Context) {
 
 // EditReleasePost response for edit release
 func EditReleasePost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.EditReleaseForm)
+	form := web.GetForm(ctx).(*forms.EditReleaseForm)
 	ctx.Data["Title"] = ctx.Tr("repo.release.edit_release")
 	ctx.Data["PageIsReleaseList"] = true
 	ctx.Data["PageIsEditRelease"] = true
diff --git a/routers/repo/release_test.go b/routers/repo/release_test.go
index 38c0d9fec0..004a6ef540 100644
--- a/routers/repo/release_test.go
+++ b/routers/repo/release_test.go
@@ -8,9 +8,9 @@ import (
 	"testing"
 
 	"code.gitea.io/gitea/models"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/test"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 )
 
 func TestNewReleasePost(t *testing.T) {
@@ -18,13 +18,13 @@ func TestNewReleasePost(t *testing.T) {
 		RepoID  int64
 		UserID  int64
 		TagName string
-		Form    auth.NewReleaseForm
+		Form    forms.NewReleaseForm
 	}{
 		{
 			RepoID:  1,
 			UserID:  2,
 			TagName: "v1.1", // pre-existing tag
-			Form: auth.NewReleaseForm{
+			Form: forms.NewReleaseForm{
 				TagName: "newtag",
 				Target:  "master",
 				Title:   "title",
@@ -35,7 +35,7 @@ func TestNewReleasePost(t *testing.T) {
 			RepoID:  1,
 			UserID:  2,
 			TagName: "newtag",
-			Form: auth.NewReleaseForm{
+			Form: forms.NewReleaseForm{
 				TagName: "newtag",
 				Target:  "master",
 				Title:   "title",
diff --git a/routers/repo/repo.go b/routers/repo/repo.go
index 68ffc4376a..1ffbb1458d 100644
--- a/routers/repo/repo.go
+++ b/routers/repo/repo.go
@@ -15,11 +15,11 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/web"
 	archiver_service "code.gitea.io/gitea/services/archiver"
+	"code.gitea.io/gitea/services/forms"
 	repo_service "code.gitea.io/gitea/services/repository"
 )
 
@@ -185,7 +185,7 @@ func handleCreateError(ctx *context.Context, owner *models.User, err error, name
 
 // CreatePost response for creating repository
 func CreatePost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.CreateRepoForm)
+	form := web.GetForm(ctx).(*forms.CreateRepoForm)
 	ctx.Data["Title"] = ctx.Tr("new_repo")
 
 	ctx.Data["Gitignores"] = models.Gitignores
diff --git a/routers/repo/setting.go b/routers/repo/setting.go
index 7d9d358311..ed6ff6e2b3 100644
--- a/routers/repo/setting.go
+++ b/routers/repo/setting.go
@@ -16,7 +16,6 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/migrations"
@@ -27,6 +26,7 @@ import (
 	"code.gitea.io/gitea/modules/validation"
 	"code.gitea.io/gitea/modules/web"
 	"code.gitea.io/gitea/routers/utils"
+	"code.gitea.io/gitea/services/forms"
 	"code.gitea.io/gitea/services/mailer"
 	mirror_service "code.gitea.io/gitea/services/mirror"
 	repo_service "code.gitea.io/gitea/services/repository"
@@ -57,7 +57,7 @@ func Settings(ctx *context.Context) {
 
 // SettingsPost response for changes of a repository
 func SettingsPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.RepoSettingForm)
+	form := web.GetForm(ctx).(*forms.RepoSettingForm)
 	ctx.Data["Title"] = ctx.Tr("repo.settings")
 	ctx.Data["PageIsSettingsOptions"] = true
 
@@ -165,7 +165,7 @@ func SettingsPost(ctx *context.Context) {
 			}
 		}
 
-		address, err := auth.ParseRemoteAddr(form.MirrorAddress, form.MirrorUsername, form.MirrorPassword)
+		address, err := forms.ParseRemoteAddr(form.MirrorAddress, form.MirrorUsername, form.MirrorPassword)
 		if err == nil {
 			err = migrations.IsMigrateURLAllowed(address, ctx.User)
 		}
@@ -883,7 +883,7 @@ func DeployKeys(ctx *context.Context) {
 
 // DeployKeysPost response for adding a deploy key of a repository
 func DeployKeysPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.AddKeyForm)
+	form := web.GetForm(ctx).(*forms.AddKeyForm)
 	ctx.Data["Title"] = ctx.Tr("repo.settings.deploy_keys")
 	ctx.Data["PageIsSettingsKeys"] = true
 
@@ -955,7 +955,7 @@ func DeleteDeployKey(ctx *context.Context) {
 }
 
 // UpdateAvatarSetting update repo's avatar
-func UpdateAvatarSetting(ctx *context.Context, form auth.AvatarForm) error {
+func UpdateAvatarSetting(ctx *context.Context, form forms.AvatarForm) error {
 	ctxRepo := ctx.Repo.Repository
 
 	if form.Avatar == nil {
@@ -993,8 +993,8 @@ func UpdateAvatarSetting(ctx *context.Context, form auth.AvatarForm) error {
 
 // SettingsAvatar save new POSTed repository avatar
 func SettingsAvatar(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.AvatarForm)
-	form.Source = auth.AvatarLocal
+	form := web.GetForm(ctx).(*forms.AvatarForm)
+	form.Source = forms.AvatarLocal
 	if err := UpdateAvatarSetting(ctx, *form); err != nil {
 		ctx.Flash.Error(err.Error())
 	} else {
diff --git a/routers/repo/setting_protected_branch.go b/routers/repo/setting_protected_branch.go
index 26d50f38b8..c395a394c2 100644
--- a/routers/repo/setting_protected_branch.go
+++ b/routers/repo/setting_protected_branch.go
@@ -13,11 +13,11 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 	pull_service "code.gitea.io/gitea/services/pull"
 )
 
@@ -171,7 +171,7 @@ func SettingsProtectedBranch(c *context.Context) {
 
 // SettingsProtectedBranchPost updates the protected branch settings
 func SettingsProtectedBranchPost(ctx *context.Context) {
-	f := web.GetForm(ctx).(*auth.ProtectBranchForm)
+	f := web.GetForm(ctx).(*forms.ProtectBranchForm)
 	branch := ctx.Params("*")
 	if !ctx.Repo.GitRepo.IsBranchExist(branch) {
 		ctx.NotFound("IsBranchExist", nil)
diff --git a/routers/repo/settings_test.go b/routers/repo/settings_test.go
index 85515121c7..5190f12d5d 100644
--- a/routers/repo/settings_test.go
+++ b/routers/repo/settings_test.go
@@ -11,11 +11,11 @@ import (
 
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/test"
 	"code.gitea.io/gitea/modules/util"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 
 	"github.com/stretchr/testify/assert"
 )
@@ -49,7 +49,7 @@ func TestAddReadOnlyDeployKey(t *testing.T) {
 	test.LoadUser(t, ctx, 2)
 	test.LoadRepo(t, ctx, 2)
 
-	addKeyForm := auth.AddKeyForm{
+	addKeyForm := forms.AddKeyForm{
 		Title:   "read-only",
 		Content: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment\n",
 	}
@@ -78,7 +78,7 @@ func TestAddReadWriteOnlyDeployKey(t *testing.T) {
 	test.LoadUser(t, ctx, 2)
 	test.LoadRepo(t, ctx, 2)
 
-	addKeyForm := auth.AddKeyForm{
+	addKeyForm := forms.AddKeyForm{
 		Title:      "read-write",
 		Content:    "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment\n",
 		IsWritable: true,
diff --git a/routers/repo/webhook.go b/routers/repo/webhook.go
index 7ff110edba..fe16d249eb 100644
--- a/routers/repo/webhook.go
+++ b/routers/repo/webhook.go
@@ -16,12 +16,12 @@ import (
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/convert"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/setting"
 	api "code.gitea.io/gitea/modules/structs"
 	"code.gitea.io/gitea/modules/util"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 	"code.gitea.io/gitea/services/webhook"
 	jsoniter "github.com/json-iterator/go"
 )
@@ -153,7 +153,7 @@ func WebhooksNew(ctx *context.Context) {
 }
 
 // ParseHookEvent convert web form content to models.HookEvent
-func ParseHookEvent(form auth.WebhookForm) *models.HookEvent {
+func ParseHookEvent(form forms.WebhookForm) *models.HookEvent {
 	return &models.HookEvent{
 		PushOnly:       form.PushOnly(),
 		SendEverything: form.SendEverything(),
@@ -184,7 +184,7 @@ func ParseHookEvent(form auth.WebhookForm) *models.HookEvent {
 
 // GiteaHooksNewPost response for creating Gitea webhook
 func GiteaHooksNewPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.NewWebhookForm)
+	form := web.GetForm(ctx).(*forms.NewWebhookForm)
 	ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook")
 	ctx.Data["PageIsSettingsHooks"] = true
 	ctx.Data["PageIsSettingsHooksNew"] = true
@@ -234,12 +234,12 @@ func GiteaHooksNewPost(ctx *context.Context) {
 
 // GogsHooksNewPost response for creating webhook
 func GogsHooksNewPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.NewGogshookForm)
+	form := web.GetForm(ctx).(*forms.NewGogshookForm)
 	newGogsWebhookPost(ctx, *form, models.GOGS)
 }
 
 // newGogsWebhookPost response for creating gogs hook
-func newGogsWebhookPost(ctx *context.Context, form auth.NewGogshookForm, kind models.HookTaskType) {
+func newGogsWebhookPost(ctx *context.Context, form forms.NewGogshookForm, kind models.HookTaskType) {
 	ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook")
 	ctx.Data["PageIsSettingsHooks"] = true
 	ctx.Data["PageIsSettingsHooksNew"] = true
@@ -288,7 +288,7 @@ func newGogsWebhookPost(ctx *context.Context, form auth.NewGogshookForm, kind mo
 
 // DiscordHooksNewPost response for creating discord hook
 func DiscordHooksNewPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.NewDiscordHookForm)
+	form := web.GetForm(ctx).(*forms.NewDiscordHookForm)
 	ctx.Data["Title"] = ctx.Tr("repo.settings")
 	ctx.Data["PageIsSettingsHooks"] = true
 	ctx.Data["PageIsSettingsHooksNew"] = true
@@ -341,7 +341,7 @@ func DiscordHooksNewPost(ctx *context.Context) {
 
 // DingtalkHooksNewPost response for creating dingtalk hook
 func DingtalkHooksNewPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.NewDingtalkHookForm)
+	form := web.GetForm(ctx).(*forms.NewDingtalkHookForm)
 	ctx.Data["Title"] = ctx.Tr("repo.settings")
 	ctx.Data["PageIsSettingsHooks"] = true
 	ctx.Data["PageIsSettingsHooksNew"] = true
@@ -384,7 +384,7 @@ func DingtalkHooksNewPost(ctx *context.Context) {
 
 // TelegramHooksNewPost response for creating telegram hook
 func TelegramHooksNewPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.NewTelegramHookForm)
+	form := web.GetForm(ctx).(*forms.NewTelegramHookForm)
 	ctx.Data["Title"] = ctx.Tr("repo.settings")
 	ctx.Data["PageIsSettingsHooks"] = true
 	ctx.Data["PageIsSettingsHooksNew"] = true
@@ -437,7 +437,7 @@ func TelegramHooksNewPost(ctx *context.Context) {
 
 // MatrixHooksNewPost response for creating a Matrix hook
 func MatrixHooksNewPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.NewMatrixHookForm)
+	form := web.GetForm(ctx).(*forms.NewMatrixHookForm)
 	ctx.Data["Title"] = ctx.Tr("repo.settings")
 	ctx.Data["PageIsSettingsHooks"] = true
 	ctx.Data["PageIsSettingsHooksNew"] = true
@@ -493,7 +493,7 @@ func MatrixHooksNewPost(ctx *context.Context) {
 
 // MSTeamsHooksNewPost response for creating MS Teams hook
 func MSTeamsHooksNewPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.NewMSTeamsHookForm)
+	form := web.GetForm(ctx).(*forms.NewMSTeamsHookForm)
 	ctx.Data["Title"] = ctx.Tr("repo.settings")
 	ctx.Data["PageIsSettingsHooks"] = true
 	ctx.Data["PageIsSettingsHooksNew"] = true
@@ -536,7 +536,7 @@ func MSTeamsHooksNewPost(ctx *context.Context) {
 
 // SlackHooksNewPost response for creating slack hook
 func SlackHooksNewPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.NewSlackHookForm)
+	form := web.GetForm(ctx).(*forms.NewSlackHookForm)
 	ctx.Data["Title"] = ctx.Tr("repo.settings")
 	ctx.Data["PageIsSettingsHooks"] = true
 	ctx.Data["PageIsSettingsHooksNew"] = true
@@ -597,7 +597,7 @@ func SlackHooksNewPost(ctx *context.Context) {
 
 // FeishuHooksNewPost response for creating feishu hook
 func FeishuHooksNewPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.NewFeishuHookForm)
+	form := web.GetForm(ctx).(*forms.NewFeishuHookForm)
 	ctx.Data["Title"] = ctx.Tr("repo.settings")
 	ctx.Data["PageIsSettingsHooks"] = true
 	ctx.Data["PageIsSettingsHooksNew"] = true
@@ -701,7 +701,7 @@ func WebHooksEdit(ctx *context.Context) {
 
 // WebHooksEditPost response for editing web hook
 func WebHooksEditPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.NewWebhookForm)
+	form := web.GetForm(ctx).(*forms.NewWebhookForm)
 	ctx.Data["Title"] = ctx.Tr("repo.settings.update_webhook")
 	ctx.Data["PageIsSettingsHooks"] = true
 	ctx.Data["PageIsSettingsHooksEdit"] = true
@@ -742,7 +742,7 @@ func WebHooksEditPost(ctx *context.Context) {
 
 // GogsHooksEditPost response for editing gogs hook
 func GogsHooksEditPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.NewGogshookForm)
+	form := web.GetForm(ctx).(*forms.NewGogshookForm)
 	ctx.Data["Title"] = ctx.Tr("repo.settings.update_webhook")
 	ctx.Data["PageIsSettingsHooks"] = true
 	ctx.Data["PageIsSettingsHooksEdit"] = true
@@ -782,7 +782,7 @@ func GogsHooksEditPost(ctx *context.Context) {
 
 // SlackHooksEditPost response for editing slack hook
 func SlackHooksEditPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.NewSlackHookForm)
+	form := web.GetForm(ctx).(*forms.NewSlackHookForm)
 	ctx.Data["Title"] = ctx.Tr("repo.settings")
 	ctx.Data["PageIsSettingsHooks"] = true
 	ctx.Data["PageIsSettingsHooksEdit"] = true
@@ -834,7 +834,7 @@ func SlackHooksEditPost(ctx *context.Context) {
 
 // DiscordHooksEditPost response for editing discord hook
 func DiscordHooksEditPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.NewDiscordHookForm)
+	form := web.GetForm(ctx).(*forms.NewDiscordHookForm)
 	ctx.Data["Title"] = ctx.Tr("repo.settings")
 	ctx.Data["PageIsSettingsHooks"] = true
 	ctx.Data["PageIsSettingsHooksEdit"] = true
@@ -878,7 +878,7 @@ func DiscordHooksEditPost(ctx *context.Context) {
 
 // DingtalkHooksEditPost response for editing discord hook
 func DingtalkHooksEditPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.NewDingtalkHookForm)
+	form := web.GetForm(ctx).(*forms.NewDingtalkHookForm)
 	ctx.Data["Title"] = ctx.Tr("repo.settings")
 	ctx.Data["PageIsSettingsHooks"] = true
 	ctx.Data["PageIsSettingsHooksEdit"] = true
@@ -911,7 +911,7 @@ func DingtalkHooksEditPost(ctx *context.Context) {
 
 // TelegramHooksEditPost response for editing discord hook
 func TelegramHooksEditPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.NewTelegramHookForm)
+	form := web.GetForm(ctx).(*forms.NewTelegramHookForm)
 	ctx.Data["Title"] = ctx.Tr("repo.settings")
 	ctx.Data["PageIsSettingsHooks"] = true
 	ctx.Data["PageIsSettingsHooksEdit"] = true
@@ -953,7 +953,7 @@ func TelegramHooksEditPost(ctx *context.Context) {
 
 // MatrixHooksEditPost response for editing a Matrix hook
 func MatrixHooksEditPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.NewMatrixHookForm)
+	form := web.GetForm(ctx).(*forms.NewMatrixHookForm)
 	ctx.Data["Title"] = ctx.Tr("repo.settings")
 	ctx.Data["PageIsSettingsHooks"] = true
 	ctx.Data["PageIsSettingsHooksEdit"] = true
@@ -998,7 +998,7 @@ func MatrixHooksEditPost(ctx *context.Context) {
 
 // MSTeamsHooksEditPost response for editing MS Teams hook
 func MSTeamsHooksEditPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.NewMSTeamsHookForm)
+	form := web.GetForm(ctx).(*forms.NewMSTeamsHookForm)
 	ctx.Data["Title"] = ctx.Tr("repo.settings")
 	ctx.Data["PageIsSettingsHooks"] = true
 	ctx.Data["PageIsSettingsHooksEdit"] = true
@@ -1031,7 +1031,7 @@ func MSTeamsHooksEditPost(ctx *context.Context) {
 
 // FeishuHooksEditPost response for editing feishu hook
 func FeishuHooksEditPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.NewFeishuHookForm)
+	form := web.GetForm(ctx).(*forms.NewFeishuHookForm)
 	ctx.Data["Title"] = ctx.Tr("repo.settings")
 	ctx.Data["PageIsSettingsHooks"] = true
 	ctx.Data["PageIsSettingsHooksEdit"] = true
diff --git a/routers/repo/wiki.go b/routers/repo/wiki.go
index 64ea4128a7..290e2e8bb2 100644
--- a/routers/repo/wiki.go
+++ b/routers/repo/wiki.go
@@ -16,7 +16,6 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/markup"
@@ -24,6 +23,7 @@ import (
 	"code.gitea.io/gitea/modules/timeutil"
 	"code.gitea.io/gitea/modules/util"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 	wiki_service "code.gitea.io/gitea/services/wiki"
 )
 
@@ -559,7 +559,7 @@ func NewWiki(ctx *context.Context) {
 
 // NewWikiPost response for wiki create request
 func NewWikiPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.NewWikiForm)
+	form := web.GetForm(ctx).(*forms.NewWikiForm)
 	ctx.Data["Title"] = ctx.Tr("repo.wiki.new_page")
 	ctx.Data["PageIsWiki"] = true
 	ctx.Data["RequireSimpleMDE"] = true
@@ -617,7 +617,7 @@ func EditWiki(ctx *context.Context) {
 
 // EditWikiPost response for wiki modify request
 func EditWikiPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.NewWikiForm)
+	form := web.GetForm(ctx).(*forms.NewWikiForm)
 	ctx.Data["Title"] = ctx.Tr("repo.wiki.new_page")
 	ctx.Data["PageIsWiki"] = true
 	ctx.Data["RequireSimpleMDE"] = true
diff --git a/routers/repo/wiki_test.go b/routers/repo/wiki_test.go
index badd07f080..4b28a5af86 100644
--- a/routers/repo/wiki_test.go
+++ b/routers/repo/wiki_test.go
@@ -10,10 +10,10 @@ import (
 	"testing"
 
 	"code.gitea.io/gitea/models"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/test"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 	wiki_service "code.gitea.io/gitea/services/wiki"
 
 	"github.com/stretchr/testify/assert"
@@ -115,7 +115,7 @@ func TestNewWikiPost(t *testing.T) {
 		ctx := test.MockContext(t, "user2/repo1/wiki/_new")
 		test.LoadUser(t, ctx, 2)
 		test.LoadRepo(t, ctx, 1)
-		web.SetForm(ctx, &auth.NewWikiForm{
+		web.SetForm(ctx, &forms.NewWikiForm{
 			Title:   title,
 			Content: content,
 			Message: message,
@@ -133,7 +133,7 @@ func TestNewWikiPost_ReservedName(t *testing.T) {
 	ctx := test.MockContext(t, "user2/repo1/wiki/_new")
 	test.LoadUser(t, ctx, 2)
 	test.LoadRepo(t, ctx, 1)
-	web.SetForm(ctx, &auth.NewWikiForm{
+	web.SetForm(ctx, &forms.NewWikiForm{
 		Title:   "_edit",
 		Content: content,
 		Message: message,
@@ -167,7 +167,7 @@ func TestEditWikiPost(t *testing.T) {
 		ctx.SetParams(":page", "Home")
 		test.LoadUser(t, ctx, 2)
 		test.LoadRepo(t, ctx, 1)
-		web.SetForm(ctx, &auth.NewWikiForm{
+		web.SetForm(ctx, &forms.NewWikiForm{
 			Title:   title,
 			Content: content,
 			Message: message,
diff --git a/routers/routes/install.go b/routers/routes/install.go
index fea396bc26..18fac8418b 100644
--- a/routers/routes/install.go
+++ b/routers/routes/install.go
@@ -9,7 +9,6 @@ import (
 	"net/http"
 	"path"
 
-	"code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/public"
 	"code.gitea.io/gitea/modules/setting"
@@ -17,6 +16,7 @@ import (
 	"code.gitea.io/gitea/modules/web"
 	"code.gitea.io/gitea/modules/web/middleware"
 	"code.gitea.io/gitea/routers"
+	"code.gitea.io/gitea/services/forms"
 
 	"gitea.com/go-chi/session"
 )
diff --git a/routers/routes/web.go b/routers/routes/web.go
index 5b382ecccb..8131c4fc87 100644
--- a/routers/routes/web.go
+++ b/routers/routes/web.go
@@ -15,7 +15,6 @@ import (
 
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/httpcache"
 	"code.gitea.io/gitea/modules/lfs"
 	"code.gitea.io/gitea/modules/log"
@@ -38,6 +37,7 @@ import (
 	"code.gitea.io/gitea/routers/repo"
 	"code.gitea.io/gitea/routers/user"
 	userSetting "code.gitea.io/gitea/routers/user/setting"
+	"code.gitea.io/gitea/services/forms"
 	"code.gitea.io/gitea/services/mailer"
 
 	// to registers all internal adapters
@@ -361,36 +361,36 @@ func RegisterRoutes(m *web.Route) {
 	// ***** START: User *****
 	m.Group("/user", func() {
 		m.Get("/login", user.SignIn)
-		m.Post("/login", bindIgnErr(auth.SignInForm{}), user.SignInPost)
+		m.Post("/login", bindIgnErr(forms.SignInForm{}), user.SignInPost)
 		m.Group("", func() {
 			m.Combo("/login/openid").
 				Get(user.SignInOpenID).
-				Post(bindIgnErr(auth.SignInOpenIDForm{}), user.SignInOpenIDPost)
+				Post(bindIgnErr(forms.SignInOpenIDForm{}), user.SignInOpenIDPost)
 		}, openIDSignInEnabled)
 		m.Group("/openid", func() {
 			m.Combo("/connect").
 				Get(user.ConnectOpenID).
-				Post(bindIgnErr(auth.ConnectOpenIDForm{}), user.ConnectOpenIDPost)
+				Post(bindIgnErr(forms.ConnectOpenIDForm{}), user.ConnectOpenIDPost)
 			m.Group("/register", func() {
 				m.Combo("").
 					Get(user.RegisterOpenID, openIDSignUpEnabled).
-					Post(bindIgnErr(auth.SignUpOpenIDForm{}), user.RegisterOpenIDPost)
+					Post(bindIgnErr(forms.SignUpOpenIDForm{}), user.RegisterOpenIDPost)
 			}, openIDSignUpEnabled)
 		}, openIDSignInEnabled)
 		m.Get("/sign_up", user.SignUp)
-		m.Post("/sign_up", bindIgnErr(auth.RegisterForm{}), user.SignUpPost)
+		m.Post("/sign_up", bindIgnErr(forms.RegisterForm{}), user.SignUpPost)
 		m.Group("/oauth2", func() {
 			m.Get("/{provider}", user.SignInOAuth)
 			m.Get("/{provider}/callback", user.SignInOAuthCallback)
 		})
 		m.Get("/link_account", user.LinkAccount)
-		m.Post("/link_account_signin", bindIgnErr(auth.SignInForm{}), user.LinkAccountPostSignIn)
-		m.Post("/link_account_signup", bindIgnErr(auth.RegisterForm{}), user.LinkAccountPostRegister)
+		m.Post("/link_account_signin", bindIgnErr(forms.SignInForm{}), user.LinkAccountPostSignIn)
+		m.Post("/link_account_signup", bindIgnErr(forms.RegisterForm{}), user.LinkAccountPostRegister)
 		m.Group("/two_factor", func() {
 			m.Get("", user.TwoFactor)
-			m.Post("", bindIgnErr(auth.TwoFactorAuthForm{}), user.TwoFactorPost)
+			m.Post("", bindIgnErr(forms.TwoFactorAuthForm{}), user.TwoFactorPost)
 			m.Get("/scratch", user.TwoFactorScratch)
-			m.Post("/scratch", bindIgnErr(auth.TwoFactorScratchAuthForm{}), user.TwoFactorScratchPost)
+			m.Post("/scratch", bindIgnErr(forms.TwoFactorScratchAuthForm{}), user.TwoFactorScratchPost)
 		})
 		m.Group("/u2f", func() {
 			m.Get("", user.U2F)
@@ -403,10 +403,10 @@ func RegisterRoutes(m *web.Route) {
 	m.Any("/user/events", events.Events)
 
 	m.Group("/login/oauth", func() {
-		m.Get("/authorize", bindIgnErr(auth.AuthorizationForm{}), user.AuthorizeOAuth)
-		m.Post("/grant", bindIgnErr(auth.GrantApplicationForm{}), user.GrantApplicationOAuth)
+		m.Get("/authorize", bindIgnErr(forms.AuthorizationForm{}), user.AuthorizeOAuth)
+		m.Post("/grant", bindIgnErr(forms.GrantApplicationForm{}), user.GrantApplicationOAuth)
 		// TODO manage redirection
-		m.Post("/authorize", bindIgnErr(auth.AuthorizationForm{}), user.AuthorizeOAuth)
+		m.Post("/authorize", bindIgnErr(forms.AuthorizationForm{}), user.AuthorizeOAuth)
 	}, ignSignInAndCsrf, reqSignIn)
 	if setting.CORSConfig.Enabled {
 		m.Post("/login/oauth/access_token", cors.Handler(cors.Options{
@@ -416,24 +416,24 @@ func RegisterRoutes(m *web.Route) {
 			AllowedMethods:   setting.CORSConfig.Methods,
 			AllowCredentials: setting.CORSConfig.AllowCredentials,
 			MaxAge:           int(setting.CORSConfig.MaxAge.Seconds()),
-		}), bindIgnErr(auth.AccessTokenForm{}), ignSignInAndCsrf, user.AccessTokenOAuth)
+		}), bindIgnErr(forms.AccessTokenForm{}), ignSignInAndCsrf, user.AccessTokenOAuth)
 	} else {
-		m.Post("/login/oauth/access_token", bindIgnErr(auth.AccessTokenForm{}), ignSignInAndCsrf, user.AccessTokenOAuth)
+		m.Post("/login/oauth/access_token", bindIgnErr(forms.AccessTokenForm{}), ignSignInAndCsrf, user.AccessTokenOAuth)
 	}
 
 	m.Group("/user/settings", func() {
 		m.Get("", userSetting.Profile)
-		m.Post("", bindIgnErr(auth.UpdateProfileForm{}), userSetting.ProfilePost)
+		m.Post("", bindIgnErr(forms.UpdateProfileForm{}), userSetting.ProfilePost)
 		m.Get("/change_password", user.MustChangePassword)
-		m.Post("/change_password", bindIgnErr(auth.MustChangePasswordForm{}), user.MustChangePasswordPost)
-		m.Post("/avatar", bindIgnErr(auth.AvatarForm{}), userSetting.AvatarPost)
+		m.Post("/change_password", bindIgnErr(forms.MustChangePasswordForm{}), user.MustChangePasswordPost)
+		m.Post("/avatar", bindIgnErr(forms.AvatarForm{}), userSetting.AvatarPost)
 		m.Post("/avatar/delete", userSetting.DeleteAvatar)
 		m.Group("/account", func() {
-			m.Combo("").Get(userSetting.Account).Post(bindIgnErr(auth.ChangePasswordForm{}), userSetting.AccountPost)
-			m.Post("/email", bindIgnErr(auth.AddEmailForm{}), userSetting.EmailPost)
+			m.Combo("").Get(userSetting.Account).Post(bindIgnErr(forms.ChangePasswordForm{}), userSetting.AccountPost)
+			m.Post("/email", bindIgnErr(forms.AddEmailForm{}), userSetting.EmailPost)
 			m.Post("/email/delete", userSetting.DeleteEmail)
 			m.Post("/delete", userSetting.DeleteAccount)
-			m.Post("/theme", bindIgnErr(auth.UpdateThemeForm{}), userSetting.UpdateUIThemePost)
+			m.Post("/theme", bindIgnErr(forms.UpdateThemeForm{}), userSetting.UpdateUIThemePost)
 		})
 		m.Group("/security", func() {
 			m.Get("", userSetting.Security)
@@ -441,15 +441,15 @@ func RegisterRoutes(m *web.Route) {
 				m.Post("/regenerate_scratch", userSetting.RegenerateScratchTwoFactor)
 				m.Post("/disable", userSetting.DisableTwoFactor)
 				m.Get("/enroll", userSetting.EnrollTwoFactor)
-				m.Post("/enroll", bindIgnErr(auth.TwoFactorAuthForm{}), userSetting.EnrollTwoFactorPost)
+				m.Post("/enroll", bindIgnErr(forms.TwoFactorAuthForm{}), userSetting.EnrollTwoFactorPost)
 			})
 			m.Group("/u2f", func() {
-				m.Post("/request_register", bindIgnErr(auth.U2FRegistrationForm{}), userSetting.U2FRegister)
+				m.Post("/request_register", bindIgnErr(forms.U2FRegistrationForm{}), userSetting.U2FRegister)
 				m.Post("/register", bindIgnErr(u2f.RegisterResponse{}), userSetting.U2FRegisterPost)
-				m.Post("/delete", bindIgnErr(auth.U2FDeleteForm{}), userSetting.U2FDelete)
+				m.Post("/delete", bindIgnErr(forms.U2FDeleteForm{}), userSetting.U2FDelete)
 			})
 			m.Group("/openid", func() {
-				m.Post("", bindIgnErr(auth.AddOpenIDForm{}), userSetting.OpenIDPost)
+				m.Post("", bindIgnErr(forms.AddOpenIDForm{}), userSetting.OpenIDPost)
 				m.Post("/delete", userSetting.DeleteOpenID)
 				m.Post("/toggle_visibility", userSetting.ToggleOpenIDVisibility)
 			}, openIDSignInEnabled)
@@ -457,17 +457,17 @@ func RegisterRoutes(m *web.Route) {
 		})
 		m.Group("/applications/oauth2", func() {
 			m.Get("/{id}", userSetting.OAuth2ApplicationShow)
-			m.Post("/{id}", bindIgnErr(auth.EditOAuth2ApplicationForm{}), userSetting.OAuthApplicationsEdit)
+			m.Post("/{id}", bindIgnErr(forms.EditOAuth2ApplicationForm{}), userSetting.OAuthApplicationsEdit)
 			m.Post("/{id}/regenerate_secret", userSetting.OAuthApplicationsRegenerateSecret)
-			m.Post("", bindIgnErr(auth.EditOAuth2ApplicationForm{}), userSetting.OAuthApplicationsPost)
+			m.Post("", bindIgnErr(forms.EditOAuth2ApplicationForm{}), userSetting.OAuthApplicationsPost)
 			m.Post("/delete", userSetting.DeleteOAuth2Application)
 			m.Post("/revoke", userSetting.RevokeOAuth2Grant)
 		})
 		m.Combo("/applications").Get(userSetting.Applications).
-			Post(bindIgnErr(auth.NewAccessTokenForm{}), userSetting.ApplicationsPost)
+			Post(bindIgnErr(forms.NewAccessTokenForm{}), userSetting.ApplicationsPost)
 		m.Post("/applications/delete", userSetting.DeleteApplication)
 		m.Combo("/keys").Get(userSetting.Keys).
-			Post(bindIgnErr(auth.AddKeyForm{}), userSetting.KeysPost)
+			Post(bindIgnErr(forms.AddKeyForm{}), userSetting.KeysPost)
 		m.Post("/keys/delete", userSetting.DeleteKey)
 		m.Get("/organization", userSetting.Organization)
 		m.Get("/repos", userSetting.Repos)
@@ -499,7 +499,7 @@ func RegisterRoutes(m *web.Route) {
 	// ***** START: Admin *****
 	m.Group("/admin", func() {
 		m.Get("", adminReq, admin.Dashboard)
-		m.Post("", adminReq, bindIgnErr(auth.AdminDashboardForm{}), admin.DashboardPost)
+		m.Post("", adminReq, bindIgnErr(forms.AdminDashboardForm{}), admin.DashboardPost)
 		m.Get("/config", admin.Config)
 		m.Post("/config/test_mail", admin.SendTestMail)
 		m.Group("/monitor", func() {
@@ -516,8 +516,8 @@ func RegisterRoutes(m *web.Route) {
 
 		m.Group("/users", func() {
 			m.Get("", admin.Users)
-			m.Combo("/new").Get(admin.NewUser).Post(bindIgnErr(auth.AdminCreateUserForm{}), admin.NewUserPost)
-			m.Combo("/{userid}").Get(admin.EditUser).Post(bindIgnErr(auth.AdminEditUserForm{}), admin.EditUserPost)
+			m.Combo("/new").Get(admin.NewUser).Post(bindIgnErr(forms.AdminCreateUserForm{}), admin.NewUserPost)
+			m.Combo("/{userid}").Get(admin.EditUser).Post(bindIgnErr(forms.AdminEditUserForm{}), admin.EditUserPost)
 			m.Post("/{userid}/delete", admin.DeleteUser)
 		})
 
@@ -540,35 +540,35 @@ func RegisterRoutes(m *web.Route) {
 			m.Get("", admin.DefaultOrSystemWebhooks)
 			m.Post("/delete", admin.DeleteDefaultOrSystemWebhook)
 			m.Get("/{id}", repo.WebHooksEdit)
-			m.Post("/gitea/{id}", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
-			m.Post("/gogs/{id}", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksEditPost)
-			m.Post("/slack/{id}", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost)
-			m.Post("/discord/{id}", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
-			m.Post("/dingtalk/{id}", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
-			m.Post("/telegram/{id}", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
-			m.Post("/matrix/{id}", bindIgnErr(auth.NewMatrixHookForm{}), repo.MatrixHooksEditPost)
-			m.Post("/msteams/{id}", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
-			m.Post("/feishu/{id}", bindIgnErr(auth.NewFeishuHookForm{}), repo.FeishuHooksEditPost)
+			m.Post("/gitea/{id}", bindIgnErr(forms.NewWebhookForm{}), repo.WebHooksEditPost)
+			m.Post("/gogs/{id}", bindIgnErr(forms.NewGogshookForm{}), repo.GogsHooksEditPost)
+			m.Post("/slack/{id}", bindIgnErr(forms.NewSlackHookForm{}), repo.SlackHooksEditPost)
+			m.Post("/discord/{id}", bindIgnErr(forms.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
+			m.Post("/dingtalk/{id}", bindIgnErr(forms.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
+			m.Post("/telegram/{id}", bindIgnErr(forms.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
+			m.Post("/matrix/{id}", bindIgnErr(forms.NewMatrixHookForm{}), repo.MatrixHooksEditPost)
+			m.Post("/msteams/{id}", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
+			m.Post("/feishu/{id}", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost)
 		}, webhooksEnabled)
 
 		m.Group("/{configType:default-hooks|system-hooks}", func() {
 			m.Get("/{type}/new", repo.WebhooksNew)
-			m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.GiteaHooksNewPost)
-			m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost)
-			m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost)
-			m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
-			m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
-			m.Post("/telegram/new", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksNewPost)
-			m.Post("/matrix/new", bindIgnErr(auth.NewMatrixHookForm{}), repo.MatrixHooksNewPost)
-			m.Post("/msteams/new", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
-			m.Post("/feishu/new", bindIgnErr(auth.NewFeishuHookForm{}), repo.FeishuHooksNewPost)
+			m.Post("/gitea/new", bindIgnErr(forms.NewWebhookForm{}), repo.GiteaHooksNewPost)
+			m.Post("/gogs/new", bindIgnErr(forms.NewGogshookForm{}), repo.GogsHooksNewPost)
+			m.Post("/slack/new", bindIgnErr(forms.NewSlackHookForm{}), repo.SlackHooksNewPost)
+			m.Post("/discord/new", bindIgnErr(forms.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
+			m.Post("/dingtalk/new", bindIgnErr(forms.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
+			m.Post("/telegram/new", bindIgnErr(forms.NewTelegramHookForm{}), repo.TelegramHooksNewPost)
+			m.Post("/matrix/new", bindIgnErr(forms.NewMatrixHookForm{}), repo.MatrixHooksNewPost)
+			m.Post("/msteams/new", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
+			m.Post("/feishu/new", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost)
 		})
 
 		m.Group("/auths", func() {
 			m.Get("", admin.Authentications)
-			m.Combo("/new").Get(admin.NewAuthSource).Post(bindIgnErr(auth.AuthenticationForm{}), admin.NewAuthSourcePost)
+			m.Combo("/new").Get(admin.NewAuthSource).Post(bindIgnErr(forms.AuthenticationForm{}), admin.NewAuthSourcePost)
 			m.Combo("/{authid}").Get(admin.EditAuthSource).
-				Post(bindIgnErr(auth.AuthenticationForm{}), admin.EditAuthSourcePost)
+				Post(bindIgnErr(forms.AuthenticationForm{}), admin.EditAuthSourcePost)
 			m.Post("/{authid}/delete", admin.DeleteAuthSource)
 		})
 
@@ -611,7 +611,7 @@ func RegisterRoutes(m *web.Route) {
 	m.Group("/org", func() {
 		m.Group("", func() {
 			m.Get("/create", org.Create)
-			m.Post("/create", bindIgnErr(auth.CreateOrgForm{}), org.CreatePost)
+			m.Post("/create", bindIgnErr(forms.CreateOrgForm{}), org.CreatePost)
 		})
 
 		m.Group("/{org}", func() {
@@ -637,48 +637,48 @@ func RegisterRoutes(m *web.Route) {
 
 		m.Group("/{org}", func() {
 			m.Get("/teams/new", org.NewTeam)
-			m.Post("/teams/new", bindIgnErr(auth.CreateTeamForm{}), org.NewTeamPost)
+			m.Post("/teams/new", bindIgnErr(forms.CreateTeamForm{}), org.NewTeamPost)
 			m.Get("/teams/{team}/edit", org.EditTeam)
-			m.Post("/teams/{team}/edit", bindIgnErr(auth.CreateTeamForm{}), org.EditTeamPost)
+			m.Post("/teams/{team}/edit", bindIgnErr(forms.CreateTeamForm{}), org.EditTeamPost)
 			m.Post("/teams/{team}/delete", org.DeleteTeam)
 
 			m.Group("/settings", func() {
 				m.Combo("").Get(org.Settings).
-					Post(bindIgnErr(auth.UpdateOrgSettingForm{}), org.SettingsPost)
-				m.Post("/avatar", bindIgnErr(auth.AvatarForm{}), org.SettingsAvatar)
+					Post(bindIgnErr(forms.UpdateOrgSettingForm{}), org.SettingsPost)
+				m.Post("/avatar", bindIgnErr(forms.AvatarForm{}), org.SettingsAvatar)
 				m.Post("/avatar/delete", org.SettingsDeleteAvatar)
 
 				m.Group("/hooks", func() {
 					m.Get("", org.Webhooks)
 					m.Post("/delete", org.DeleteWebhook)
 					m.Get("/{type}/new", repo.WebhooksNew)
-					m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.GiteaHooksNewPost)
-					m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost)
-					m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost)
-					m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
-					m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
-					m.Post("/telegram/new", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksNewPost)
-					m.Post("/matrix/new", bindIgnErr(auth.NewMatrixHookForm{}), repo.MatrixHooksNewPost)
-					m.Post("/msteams/new", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
-					m.Post("/feishu/new", bindIgnErr(auth.NewFeishuHookForm{}), repo.FeishuHooksNewPost)
+					m.Post("/gitea/new", bindIgnErr(forms.NewWebhookForm{}), repo.GiteaHooksNewPost)
+					m.Post("/gogs/new", bindIgnErr(forms.NewGogshookForm{}), repo.GogsHooksNewPost)
+					m.Post("/slack/new", bindIgnErr(forms.NewSlackHookForm{}), repo.SlackHooksNewPost)
+					m.Post("/discord/new", bindIgnErr(forms.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
+					m.Post("/dingtalk/new", bindIgnErr(forms.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
+					m.Post("/telegram/new", bindIgnErr(forms.NewTelegramHookForm{}), repo.TelegramHooksNewPost)
+					m.Post("/matrix/new", bindIgnErr(forms.NewMatrixHookForm{}), repo.MatrixHooksNewPost)
+					m.Post("/msteams/new", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
+					m.Post("/feishu/new", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost)
 					m.Get("/{id}", repo.WebHooksEdit)
-					m.Post("/gitea/{id}", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
-					m.Post("/gogs/{id}", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksEditPost)
-					m.Post("/slack/{id}", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost)
-					m.Post("/discord/{id}", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
-					m.Post("/dingtalk/{id}", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
-					m.Post("/telegram/{id}", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
-					m.Post("/matrix/{id}", bindIgnErr(auth.NewMatrixHookForm{}), repo.MatrixHooksEditPost)
-					m.Post("/msteams/{id}", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
-					m.Post("/feishu/{id}", bindIgnErr(auth.NewFeishuHookForm{}), repo.FeishuHooksEditPost)
+					m.Post("/gitea/{id}", bindIgnErr(forms.NewWebhookForm{}), repo.WebHooksEditPost)
+					m.Post("/gogs/{id}", bindIgnErr(forms.NewGogshookForm{}), repo.GogsHooksEditPost)
+					m.Post("/slack/{id}", bindIgnErr(forms.NewSlackHookForm{}), repo.SlackHooksEditPost)
+					m.Post("/discord/{id}", bindIgnErr(forms.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
+					m.Post("/dingtalk/{id}", bindIgnErr(forms.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
+					m.Post("/telegram/{id}", bindIgnErr(forms.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
+					m.Post("/matrix/{id}", bindIgnErr(forms.NewMatrixHookForm{}), repo.MatrixHooksEditPost)
+					m.Post("/msteams/{id}", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
+					m.Post("/feishu/{id}", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost)
 				}, webhooksEnabled)
 
 				m.Group("/labels", func() {
 					m.Get("", org.RetrieveLabels, org.Labels)
-					m.Post("/new", bindIgnErr(auth.CreateLabelForm{}), org.NewLabel)
-					m.Post("/edit", bindIgnErr(auth.CreateLabelForm{}), org.UpdateLabel)
+					m.Post("/new", bindIgnErr(forms.CreateLabelForm{}), org.NewLabel)
+					m.Post("/edit", bindIgnErr(forms.CreateLabelForm{}), org.UpdateLabel)
 					m.Post("/delete", org.DeleteLabel)
-					m.Post("/initialize", bindIgnErr(auth.InitializeLabelsForm{}), org.InitializeLabels)
+					m.Post("/initialize", bindIgnErr(forms.InitializeLabelsForm{}), org.InitializeLabels)
 				})
 
 				m.Route("/delete", "GET,POST", org.SettingsDelete)
@@ -690,12 +690,12 @@ func RegisterRoutes(m *web.Route) {
 	// ***** START: Repository *****
 	m.Group("/repo", func() {
 		m.Get("/create", repo.Create)
-		m.Post("/create", bindIgnErr(auth.CreateRepoForm{}), repo.CreatePost)
+		m.Post("/create", bindIgnErr(forms.CreateRepoForm{}), repo.CreatePost)
 		m.Get("/migrate", repo.Migrate)
-		m.Post("/migrate", bindIgnErr(auth.MigrateRepoForm{}), repo.MigratePost)
+		m.Post("/migrate", bindIgnErr(forms.MigrateRepoForm{}), repo.MigratePost)
 		m.Group("/fork", func() {
 			m.Combo("/{repoid}").Get(repo.Fork).
-				Post(bindIgnErr(auth.CreateRepoForm{}), repo.ForkPost)
+				Post(bindIgnErr(forms.CreateRepoForm{}), repo.ForkPost)
 		}, context.RepoIDAssignment(), context.UnitTypes(), reqRepoCodeReader)
 	}, reqSignIn)
 
@@ -705,8 +705,8 @@ func RegisterRoutes(m *web.Route) {
 	m.Group("/{username}/{reponame}", func() {
 		m.Group("/settings", func() {
 			m.Combo("").Get(repo.Settings).
-				Post(bindIgnErr(auth.RepoSettingForm{}), repo.SettingsPost)
-			m.Post("/avatar", bindIgnErr(auth.AvatarForm{}), repo.SettingsAvatar)
+				Post(bindIgnErr(forms.RepoSettingForm{}), repo.SettingsPost)
+			m.Post("/avatar", bindIgnErr(forms.AvatarForm{}), repo.SettingsAvatar)
 			m.Post("/avatar/delete", repo.SettingsDeleteAvatar)
 
 			m.Group("/collaboration", func() {
@@ -721,7 +721,7 @@ func RegisterRoutes(m *web.Route) {
 			m.Group("/branches", func() {
 				m.Combo("").Get(repo.ProtectedBranch).Post(repo.ProtectedBranchPost)
 				m.Combo("/*").Get(repo.SettingsProtectedBranch).
-					Post(bindIgnErr(auth.ProtectBranchForm{}), context.RepoMustNotBeArchived(), repo.SettingsProtectedBranchPost)
+					Post(bindIgnErr(forms.ProtectBranchForm{}), context.RepoMustNotBeArchived(), repo.SettingsProtectedBranchPost)
 			}, repo.MustBeNotEmpty)
 
 			m.Group("/hooks/git", func() {
@@ -734,31 +734,31 @@ func RegisterRoutes(m *web.Route) {
 				m.Get("", repo.Webhooks)
 				m.Post("/delete", repo.DeleteWebhook)
 				m.Get("/{type}/new", repo.WebhooksNew)
-				m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.GiteaHooksNewPost)
-				m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost)
-				m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost)
-				m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
-				m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
-				m.Post("/telegram/new", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksNewPost)
-				m.Post("/matrix/new", bindIgnErr(auth.NewMatrixHookForm{}), repo.MatrixHooksNewPost)
-				m.Post("/msteams/new", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
-				m.Post("/feishu/new", bindIgnErr(auth.NewFeishuHookForm{}), repo.FeishuHooksNewPost)
+				m.Post("/gitea/new", bindIgnErr(forms.NewWebhookForm{}), repo.GiteaHooksNewPost)
+				m.Post("/gogs/new", bindIgnErr(forms.NewGogshookForm{}), repo.GogsHooksNewPost)
+				m.Post("/slack/new", bindIgnErr(forms.NewSlackHookForm{}), repo.SlackHooksNewPost)
+				m.Post("/discord/new", bindIgnErr(forms.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
+				m.Post("/dingtalk/new", bindIgnErr(forms.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
+				m.Post("/telegram/new", bindIgnErr(forms.NewTelegramHookForm{}), repo.TelegramHooksNewPost)
+				m.Post("/matrix/new", bindIgnErr(forms.NewMatrixHookForm{}), repo.MatrixHooksNewPost)
+				m.Post("/msteams/new", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
+				m.Post("/feishu/new", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost)
 				m.Get("/{id}", repo.WebHooksEdit)
 				m.Post("/{id}/test", repo.TestWebhook)
-				m.Post("/gitea/{id}", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
-				m.Post("/gogs/{id}", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksEditPost)
-				m.Post("/slack/{id}", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost)
-				m.Post("/discord/{id}", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
-				m.Post("/dingtalk/{id}", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
-				m.Post("/telegram/{id}", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
-				m.Post("/matrix/{id}", bindIgnErr(auth.NewMatrixHookForm{}), repo.MatrixHooksEditPost)
-				m.Post("/msteams/{id}", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
-				m.Post("/feishu/{id}", bindIgnErr(auth.NewFeishuHookForm{}), repo.FeishuHooksEditPost)
+				m.Post("/gitea/{id}", bindIgnErr(forms.NewWebhookForm{}), repo.WebHooksEditPost)
+				m.Post("/gogs/{id}", bindIgnErr(forms.NewGogshookForm{}), repo.GogsHooksEditPost)
+				m.Post("/slack/{id}", bindIgnErr(forms.NewSlackHookForm{}), repo.SlackHooksEditPost)
+				m.Post("/discord/{id}", bindIgnErr(forms.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
+				m.Post("/dingtalk/{id}", bindIgnErr(forms.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
+				m.Post("/telegram/{id}", bindIgnErr(forms.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
+				m.Post("/matrix/{id}", bindIgnErr(forms.NewMatrixHookForm{}), repo.MatrixHooksEditPost)
+				m.Post("/msteams/{id}", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
+				m.Post("/feishu/{id}", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost)
 			}, webhooksEnabled)
 
 			m.Group("/keys", func() {
 				m.Combo("").Get(repo.DeployKeys).
-					Post(bindIgnErr(auth.AddKeyForm{}), repo.DeployKeysPost)
+					Post(bindIgnErr(forms.AddKeyForm{}), repo.DeployKeysPost)
 				m.Post("/delete", repo.DeleteDeployKey)
 			})
 
@@ -791,7 +791,7 @@ func RegisterRoutes(m *web.Route) {
 		}, reqRepoIssuesOrPullsReader, context.RepoRef())
 		m.Combo("/compare/*", repo.MustBeNotEmpty, reqRepoCodeReader, repo.SetEditorconfigIfExists).
 			Get(ignSignIn, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff).
-			Post(reqSignIn, context.RepoMustNotBeArchived(), reqRepoPullsReader, repo.MustAllowPulls, bindIgnErr(auth.CreateIssueForm{}), repo.SetWhitespaceBehavior, repo.CompareAndPullRequestPost)
+			Post(reqSignIn, context.RepoMustNotBeArchived(), reqRepoPullsReader, repo.MustAllowPulls, bindIgnErr(forms.CreateIssueForm{}), repo.SetWhitespaceBehavior, repo.CompareAndPullRequestPost)
 	}, context.RepoAssignment(), context.UnitTypes())
 
 	// Grouping for those endpoints that do require authentication
@@ -799,7 +799,7 @@ func RegisterRoutes(m *web.Route) {
 		m.Group("/issues", func() {
 			m.Group("/new", func() {
 				m.Combo("").Get(context.RepoRef(), repo.NewIssue).
-					Post(bindIgnErr(auth.CreateIssueForm{}), repo.NewIssuePost)
+					Post(bindIgnErr(forms.CreateIssueForm{}), repo.NewIssuePost)
 				m.Get("/choose", context.RepoRef(), repo.NewIssueChooseTemplate)
 			})
 		}, context.RepoMustNotBeArchived(), reqRepoIssueReader)
@@ -815,17 +815,17 @@ func RegisterRoutes(m *web.Route) {
 					m.Post("/add", repo.AddDependency)
 					m.Post("/delete", repo.RemoveDependency)
 				})
-				m.Combo("/comments").Post(repo.MustAllowUserComment, bindIgnErr(auth.CreateCommentForm{}), repo.NewComment)
+				m.Combo("/comments").Post(repo.MustAllowUserComment, bindIgnErr(forms.CreateCommentForm{}), repo.NewComment)
 				m.Group("/times", func() {
-					m.Post("/add", bindIgnErr(auth.AddTimeManuallyForm{}), repo.AddTimeManually)
+					m.Post("/add", bindIgnErr(forms.AddTimeManuallyForm{}), repo.AddTimeManually)
 					m.Post("/{timeid}/delete", repo.DeleteTime)
 					m.Group("/stopwatch", func() {
 						m.Post("/toggle", repo.IssueStopwatch)
 						m.Post("/cancel", repo.CancelStopwatch)
 					})
 				})
-				m.Post("/reactions/{action}", bindIgnErr(auth.ReactionForm{}), repo.ChangeIssueReaction)
-				m.Post("/lock", reqRepoIssueWriter, bindIgnErr(auth.IssueLockForm{}), repo.LockIssue)
+				m.Post("/reactions/{action}", bindIgnErr(forms.ReactionForm{}), repo.ChangeIssueReaction)
+				m.Post("/lock", reqRepoIssueWriter, bindIgnErr(forms.IssueLockForm{}), repo.LockIssue)
 				m.Post("/unlock", reqRepoIssueWriter, repo.UnlockIssue)
 			}, context.RepoMustNotBeArchived())
 			m.Group("/{index}", func() {
@@ -838,7 +838,7 @@ func RegisterRoutes(m *web.Route) {
 			m.Post("/projects", reqRepoIssuesOrPullsWriter, repo.UpdateIssueProject)
 			m.Post("/assignee", reqRepoIssuesOrPullsWriter, repo.UpdateIssueAssignee)
 			m.Post("/request_review", reqRepoIssuesOrPullsReader, repo.UpdatePullReviewRequest)
-			m.Post("/dismiss_review", reqRepoAdmin, bindIgnErr(auth.DismissReviewForm{}), repo.DismissReview)
+			m.Post("/dismiss_review", reqRepoAdmin, bindIgnErr(forms.DismissReviewForm{}), repo.DismissReview)
 			m.Post("/status", reqRepoIssuesOrPullsWriter, repo.UpdateIssueStatus)
 			m.Post("/resolve_conversation", reqRepoIssuesOrPullsReader, repo.UpdateResolveConversation)
 			m.Post("/attachments", repo.UploadIssueAttachment)
@@ -847,22 +847,22 @@ func RegisterRoutes(m *web.Route) {
 		m.Group("/comments/{id}", func() {
 			m.Post("", repo.UpdateCommentContent)
 			m.Post("/delete", repo.DeleteComment)
-			m.Post("/reactions/{action}", bindIgnErr(auth.ReactionForm{}), repo.ChangeCommentReaction)
+			m.Post("/reactions/{action}", bindIgnErr(forms.ReactionForm{}), repo.ChangeCommentReaction)
 		}, context.RepoMustNotBeArchived())
 		m.Group("/comments/{id}", func() {
 			m.Get("/attachments", repo.GetCommentAttachments)
 		})
 		m.Group("/labels", func() {
-			m.Post("/new", bindIgnErr(auth.CreateLabelForm{}), repo.NewLabel)
-			m.Post("/edit", bindIgnErr(auth.CreateLabelForm{}), repo.UpdateLabel)
+			m.Post("/new", bindIgnErr(forms.CreateLabelForm{}), repo.NewLabel)
+			m.Post("/edit", bindIgnErr(forms.CreateLabelForm{}), repo.UpdateLabel)
 			m.Post("/delete", repo.DeleteLabel)
-			m.Post("/initialize", bindIgnErr(auth.InitializeLabelsForm{}), repo.InitializeLabels)
+			m.Post("/initialize", bindIgnErr(forms.InitializeLabelsForm{}), repo.InitializeLabels)
 		}, context.RepoMustNotBeArchived(), reqRepoIssuesOrPullsWriter, context.RepoRef())
 		m.Group("/milestones", func() {
 			m.Combo("/new").Get(repo.NewMilestone).
-				Post(bindIgnErr(auth.CreateMilestoneForm{}), repo.NewMilestonePost)
+				Post(bindIgnErr(forms.CreateMilestoneForm{}), repo.NewMilestonePost)
 			m.Get("/{id}/edit", repo.EditMilestone)
-			m.Post("/{id}/edit", bindIgnErr(auth.CreateMilestoneForm{}), repo.EditMilestonePost)
+			m.Post("/{id}/edit", bindIgnErr(forms.CreateMilestoneForm{}), repo.EditMilestonePost)
 			m.Post("/{id}/{action}", repo.ChangeMilestoneStatus)
 			m.Post("/delete", repo.DeleteMilestone)
 		}, context.RepoMustNotBeArchived(), reqRepoIssuesOrPullsWriter, context.RepoRef())
@@ -873,19 +873,19 @@ func RegisterRoutes(m *web.Route) {
 		m.Group("", func() {
 			m.Group("", func() {
 				m.Combo("/_edit/*").Get(repo.EditFile).
-					Post(bindIgnErr(auth.EditRepoFileForm{}), repo.EditFilePost)
+					Post(bindIgnErr(forms.EditRepoFileForm{}), repo.EditFilePost)
 				m.Combo("/_new/*").Get(repo.NewFile).
-					Post(bindIgnErr(auth.EditRepoFileForm{}), repo.NewFilePost)
-				m.Post("/_preview/*", bindIgnErr(auth.EditPreviewDiffForm{}), repo.DiffPreviewPost)
+					Post(bindIgnErr(forms.EditRepoFileForm{}), repo.NewFilePost)
+				m.Post("/_preview/*", bindIgnErr(forms.EditPreviewDiffForm{}), repo.DiffPreviewPost)
 				m.Combo("/_delete/*").Get(repo.DeleteFile).
-					Post(bindIgnErr(auth.DeleteRepoFileForm{}), repo.DeleteFilePost)
+					Post(bindIgnErr(forms.DeleteRepoFileForm{}), repo.DeleteFilePost)
 				m.Combo("/_upload/*", repo.MustBeAbleToUpload).
 					Get(repo.UploadFile).
-					Post(bindIgnErr(auth.UploadRepoFileForm{}), repo.UploadFilePost)
+					Post(bindIgnErr(forms.UploadRepoFileForm{}), repo.UploadFilePost)
 			}, context.RepoRefByType(context.RepoRefBranch), repo.MustBeEditable)
 			m.Group("", func() {
 				m.Post("/upload-file", repo.UploadFileToServer)
-				m.Post("/upload-remove", bindIgnErr(auth.RemoveUploadFileForm{}), repo.RemoveUploadFileFromServer)
+				m.Post("/upload-remove", bindIgnErr(forms.RemoveUploadFileForm{}), repo.RemoveUploadFileFromServer)
 			}, context.RepoRef(), repo.MustBeEditable, repo.MustBeAbleToUpload)
 		}, context.RepoMustNotBeArchived(), reqRepoCodeWriter, repo.MustBeNotEmpty)
 
@@ -894,7 +894,7 @@ func RegisterRoutes(m *web.Route) {
 				m.Post("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.CreateBranch)
 				m.Post("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.CreateBranch)
 				m.Post("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.CreateBranch)
-			}, bindIgnErr(auth.NewBranchForm{}))
+			}, bindIgnErr(forms.NewBranchForm{}))
 			m.Post("/delete", repo.DeleteBranchPost)
 			m.Post("/restore", repo.RestoreBranchPost)
 		}, context.RepoMustNotBeArchived(), reqRepoCodeWriter, repo.MustBeNotEmpty)
@@ -913,7 +913,7 @@ func RegisterRoutes(m *web.Route) {
 		}, repo.MustBeNotEmpty, reqRepoReleaseReader, context.RepoRefByType(context.RepoRefTag))
 		m.Group("/releases", func() {
 			m.Get("/new", repo.NewRelease)
-			m.Post("/new", bindIgnErr(auth.NewReleaseForm{}), repo.NewReleasePost)
+			m.Post("/new", bindIgnErr(forms.NewReleaseForm{}), repo.NewReleasePost)
 			m.Post("/delete", repo.DeleteRelease)
 			m.Post("/attachments", repo.UploadReleaseAttachment)
 			m.Post("/attachments/remove", repo.DeleteAttachment)
@@ -922,7 +922,7 @@ func RegisterRoutes(m *web.Route) {
 			repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoCodeWriter, context.RepoRef())
 		m.Group("/releases", func() {
 			m.Get("/edit/*", repo.EditRelease)
-			m.Post("/edit/*", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost)
+			m.Post("/edit/*", bindIgnErr(forms.EditReleaseForm{}), repo.EditReleasePost)
 		}, reqSignIn, repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoReleaseWriter, func(ctx *context.Context) {
 			var err error
 			ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch)
@@ -956,17 +956,17 @@ func RegisterRoutes(m *web.Route) {
 			m.Get("/{id}", repo.ViewProject)
 			m.Group("", func() {
 				m.Get("/new", repo.NewProject)
-				m.Post("/new", bindIgnErr(auth.CreateProjectForm{}), repo.NewProjectPost)
+				m.Post("/new", bindIgnErr(forms.CreateProjectForm{}), repo.NewProjectPost)
 				m.Group("/{id}", func() {
-					m.Post("", bindIgnErr(auth.EditProjectBoardForm{}), repo.AddBoardToProjectPost)
+					m.Post("", bindIgnErr(forms.EditProjectBoardForm{}), repo.AddBoardToProjectPost)
 					m.Post("/delete", repo.DeleteProject)
 
 					m.Get("/edit", repo.EditProject)
-					m.Post("/edit", bindIgnErr(auth.CreateProjectForm{}), repo.EditProjectPost)
+					m.Post("/edit", bindIgnErr(forms.CreateProjectForm{}), repo.EditProjectPost)
 					m.Post("/{action:open|close}", repo.ChangeProjectStatus)
 
 					m.Group("/{boardID}", func() {
-						m.Put("", bindIgnErr(auth.EditProjectBoardForm{}), repo.EditProjectBoard)
+						m.Put("", bindIgnErr(forms.EditProjectBoardForm{}), repo.EditProjectBoard)
 						m.Delete("", repo.DeleteProjectBoard)
 						m.Post("/default", repo.SetDefaultProjectBoard)
 
@@ -986,9 +986,9 @@ func RegisterRoutes(m *web.Route) {
 
 			m.Group("", func() {
 				m.Combo("/_new").Get(repo.NewWiki).
-					Post(bindIgnErr(auth.NewWikiForm{}), repo.NewWikiPost)
+					Post(bindIgnErr(forms.NewWikiForm{}), repo.NewWikiPost)
 				m.Combo("/{page}/_edit").Get(repo.EditWiki).
-					Post(bindIgnErr(auth.NewWikiForm{}), repo.EditWikiPost)
+					Post(bindIgnErr(forms.NewWikiForm{}), repo.EditWikiPost)
 				m.Post("/{page}/delete", repo.DeleteWikiPagePost)
 			}, context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter)
 		}, repo.MustEnableWiki, context.RepoRef(), func(ctx *context.Context) {
@@ -1026,15 +1026,15 @@ func RegisterRoutes(m *web.Route) {
 			m.Get(".diff", repo.DownloadPullDiff)
 			m.Get(".patch", repo.DownloadPullPatch)
 			m.Get("/commits", context.RepoRef(), repo.ViewPullCommits)
-			m.Post("/merge", context.RepoMustNotBeArchived(), bindIgnErr(auth.MergePullRequestForm{}), repo.MergePullRequest)
+			m.Post("/merge", context.RepoMustNotBeArchived(), bindIgnErr(forms.MergePullRequestForm{}), repo.MergePullRequest)
 			m.Post("/update", repo.UpdatePullRequest)
 			m.Post("/cleanup", context.RepoMustNotBeArchived(), context.RepoRef(), repo.CleanUpPullRequest)
 			m.Group("/files", func() {
 				m.Get("", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.ViewPullFiles)
 				m.Group("/reviews", func() {
 					m.Get("/new_comment", repo.RenderNewCodeCommentForm)
-					m.Post("/comments", bindIgnErr(auth.CodeCommentForm{}), repo.CreateCodeComment)
-					m.Post("/submit", bindIgnErr(auth.SubmitReviewForm{}), repo.SubmitReview)
+					m.Post("/comments", bindIgnErr(forms.CodeCommentForm{}), repo.CreateCodeComment)
+					m.Post("/submit", bindIgnErr(forms.SubmitReviewForm{}), repo.SubmitReview)
 				}, context.RepoMustNotBeArchived())
 			})
 		}, repo.MustAllowPulls)
diff --git a/routers/user/auth.go b/routers/user/auth.go
index a6d3ace7ba..1692a396cc 100644
--- a/routers/user/auth.go
+++ b/routers/user/auth.go
@@ -16,7 +16,6 @@ import (
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/eventsource"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/hcaptcha"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/password"
@@ -27,6 +26,7 @@ import (
 	"code.gitea.io/gitea/modules/web/middleware"
 	"code.gitea.io/gitea/routers/utils"
 	"code.gitea.io/gitea/services/externalaccount"
+	"code.gitea.io/gitea/services/forms"
 	"code.gitea.io/gitea/services/mailer"
 
 	"github.com/markbates/goth"
@@ -171,7 +171,7 @@ func SignInPost(ctx *context.Context) {
 		return
 	}
 
-	form := web.GetForm(ctx).(*auth.SignInForm)
+	form := web.GetForm(ctx).(*forms.SignInForm)
 	u, err := models.UserSignIn(form.UserName, form.Password)
 	if err != nil {
 		if models.IsErrUserNotExist(err) {
@@ -253,7 +253,7 @@ func TwoFactor(ctx *context.Context) {
 
 // TwoFactorPost validates a user's two-factor authentication token.
 func TwoFactorPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.TwoFactorAuthForm)
+	form := web.GetForm(ctx).(*forms.TwoFactorAuthForm)
 	ctx.Data["Title"] = ctx.Tr("twofa")
 
 	// Ensure user is in a 2FA session.
@@ -309,7 +309,7 @@ func TwoFactorPost(ctx *context.Context) {
 		return
 	}
 
-	ctx.RenderWithErr(ctx.Tr("auth.twofa_passcode_incorrect"), tplTwofa, auth.TwoFactorAuthForm{})
+	ctx.RenderWithErr(ctx.Tr("auth.twofa_passcode_incorrect"), tplTwofa, forms.TwoFactorAuthForm{})
 }
 
 // TwoFactorScratch shows the scratch code form for two-factor authentication.
@@ -332,7 +332,7 @@ func TwoFactorScratch(ctx *context.Context) {
 
 // TwoFactorScratchPost validates and invalidates a user's two-factor scratch token.
 func TwoFactorScratchPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.TwoFactorScratchAuthForm)
+	form := web.GetForm(ctx).(*forms.TwoFactorScratchAuthForm)
 	ctx.Data["Title"] = ctx.Tr("twofa_scratch")
 
 	// Ensure user is in a 2FA session.
@@ -375,7 +375,7 @@ func TwoFactorScratchPost(ctx *context.Context) {
 		return
 	}
 
-	ctx.RenderWithErr(ctx.Tr("auth.twofa_scratch_token_incorrect"), tplTwofaScratch, auth.TwoFactorScratchAuthForm{})
+	ctx.RenderWithErr(ctx.Tr("auth.twofa_scratch_token_incorrect"), tplTwofaScratch, forms.TwoFactorScratchAuthForm{})
 }
 
 // U2F shows the U2F login page
@@ -796,7 +796,7 @@ func LinkAccount(ctx *context.Context) {
 
 // LinkAccountPostSignIn handle the coupling of external account with another account using signIn
 func LinkAccountPostSignIn(ctx *context.Context) {
-	signInForm := web.GetForm(ctx).(*auth.SignInForm)
+	signInForm := web.GetForm(ctx).(*forms.SignInForm)
 	ctx.Data["DisablePassword"] = !setting.Service.RequireExternalRegistrationPassword || setting.Service.AllowOnlyExternalRegistration
 	ctx.Data["Title"] = ctx.Tr("link_account")
 	ctx.Data["LinkAccountMode"] = true
@@ -881,7 +881,7 @@ func LinkAccountPostSignIn(ctx *context.Context) {
 
 // LinkAccountPostRegister handle the creation of a new account for an external account using signUp
 func LinkAccountPostRegister(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.RegisterForm)
+	form := web.GetForm(ctx).(*forms.RegisterForm)
 	// TODO Make insecure passwords optional for local accounts also,
 	//      once email-based Second-Factor Auth is available
 	ctx.Data["DisablePassword"] = !setting.Service.RequireExternalRegistrationPassword || setting.Service.AllowOnlyExternalRegistration
@@ -1089,7 +1089,7 @@ func SignUp(ctx *context.Context) {
 
 // SignUpPost response for sign up information submission
 func SignUpPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.RegisterForm)
+	form := web.GetForm(ctx).(*forms.RegisterForm)
 	ctx.Data["Title"] = ctx.Tr("sign_up")
 
 	ctx.Data["SignUpLink"] = setting.AppSubURL + "/user/sign_up"
@@ -1584,7 +1584,7 @@ func MustChangePassword(ctx *context.Context) {
 // MustChangePasswordPost response for updating a user's password after his/her
 // account was created by an admin
 func MustChangePasswordPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.MustChangePasswordForm)
+	form := web.GetForm(ctx).(*forms.MustChangePasswordForm)
 	ctx.Data["Title"] = ctx.Tr("auth.must_change_password")
 	ctx.Data["ChangePasscodeLink"] = setting.AppSubURL + "/user/settings/change_password"
 	if ctx.HasError() {
diff --git a/routers/user/auth_openid.go b/routers/user/auth_openid.go
index 7db61dc09b..93a8861da7 100644
--- a/routers/user/auth_openid.go
+++ b/routers/user/auth_openid.go
@@ -13,7 +13,6 @@ import (
 	"code.gitea.io/gitea/modules/auth/openid"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/generate"
 	"code.gitea.io/gitea/modules/hcaptcha"
 	"code.gitea.io/gitea/modules/log"
@@ -22,6 +21,7 @@ import (
 	"code.gitea.io/gitea/modules/timeutil"
 	"code.gitea.io/gitea/modules/web"
 	"code.gitea.io/gitea/modules/web/middleware"
+	"code.gitea.io/gitea/services/forms"
 	"code.gitea.io/gitea/services/mailer"
 )
 
@@ -92,7 +92,7 @@ func allowedOpenIDURI(uri string) (err error) {
 
 // SignInOpenIDPost response for openid sign in request
 func SignInOpenIDPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.SignInOpenIDForm)
+	form := web.GetForm(ctx).(*forms.SignInOpenIDForm)
 	ctx.Data["Title"] = ctx.Tr("sign_in")
 	ctx.Data["PageIsSignIn"] = true
 	ctx.Data["PageIsLoginOpenID"] = true
@@ -152,7 +152,7 @@ func signInOpenIDVerify(ctx *context.Context) {
 
 	var id, err = openid.Verify(fullURL)
 	if err != nil {
-		ctx.RenderWithErr(err.Error(), tplSignInOpenID, &auth.SignInOpenIDForm{
+		ctx.RenderWithErr(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{
 			Openid: id,
 		})
 		return
@@ -166,7 +166,7 @@ func signInOpenIDVerify(ctx *context.Context) {
 	u, err := models.GetUserByOpenID(id)
 	if err != nil {
 		if !models.IsErrUserNotExist(err) {
-			ctx.RenderWithErr(err.Error(), tplSignInOpenID, &auth.SignInOpenIDForm{
+			ctx.RenderWithErr(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{
 				Openid: id,
 			})
 			return
@@ -185,14 +185,14 @@ func signInOpenIDVerify(ctx *context.Context) {
 
 	parsedURL, err := url.Parse(fullURL)
 	if err != nil {
-		ctx.RenderWithErr(err.Error(), tplSignInOpenID, &auth.SignInOpenIDForm{
+		ctx.RenderWithErr(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{
 			Openid: id,
 		})
 		return
 	}
 	values, err := url.ParseQuery(parsedURL.RawQuery)
 	if err != nil {
-		ctx.RenderWithErr(err.Error(), tplSignInOpenID, &auth.SignInOpenIDForm{
+		ctx.RenderWithErr(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{
 			Openid: id,
 		})
 		return
@@ -206,7 +206,7 @@ func signInOpenIDVerify(ctx *context.Context) {
 		u, err = models.GetUserByEmail(email)
 		if err != nil {
 			if !models.IsErrUserNotExist(err) {
-				ctx.RenderWithErr(err.Error(), tplSignInOpenID, &auth.SignInOpenIDForm{
+				ctx.RenderWithErr(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{
 					Openid: id,
 				})
 				return
@@ -222,7 +222,7 @@ func signInOpenIDVerify(ctx *context.Context) {
 		u, _ = models.GetUserByName(nickname)
 		if err != nil {
 			if !models.IsErrUserNotExist(err) {
-				ctx.RenderWithErr(err.Error(), tplSignInOpenID, &auth.SignInOpenIDForm{
+				ctx.RenderWithErr(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{
 					Openid: id,
 				})
 				return
@@ -279,7 +279,7 @@ func ConnectOpenID(ctx *context.Context) {
 
 // ConnectOpenIDPost handles submission of a form to connect an OpenID URI to an existing account
 func ConnectOpenIDPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.ConnectOpenIDForm)
+	form := web.GetForm(ctx).(*forms.ConnectOpenIDForm)
 	oid, _ := ctx.Session.Get("openid_verified_uri").(string)
 	if oid == "" {
 		ctx.Redirect(setting.AppSubURL + "/user/login/openid")
@@ -350,7 +350,7 @@ func RegisterOpenID(ctx *context.Context) {
 
 // RegisterOpenIDPost handles submission of a form to create a new user authenticated via an OpenID URI
 func RegisterOpenIDPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.SignUpOpenIDForm)
+	form := web.GetForm(ctx).(*forms.SignUpOpenIDForm)
 	oid, _ := ctx.Session.Get("openid_verified_uri").(string)
 	if oid == "" {
 		ctx.Redirect(setting.AppSubURL + "/user/login/openid")
diff --git a/routers/user/oauth.go b/routers/user/oauth.go
index 4502c2bd39..c8c846c687 100644
--- a/routers/user/oauth.go
+++ b/routers/user/oauth.go
@@ -15,11 +15,11 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/timeutil"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 
 	"gitea.com/go-chi/binding"
 	"github.com/dgrijalva/jwt-go"
@@ -195,7 +195,7 @@ func newAccessTokenResponse(grant *models.OAuth2Grant, clientSecret string) (*Ac
 
 // AuthorizeOAuth manages authorize requests
 func AuthorizeOAuth(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.AuthorizationForm)
+	form := web.GetForm(ctx).(*forms.AuthorizationForm)
 	errs := binding.Errors{}
 	errs = form.Validate(ctx.Req, errs)
 	if len(errs) > 0 {
@@ -345,7 +345,7 @@ func AuthorizeOAuth(ctx *context.Context) {
 
 // GrantApplicationOAuth manages the post request submitted when a user grants access to an application
 func GrantApplicationOAuth(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.GrantApplicationForm)
+	form := web.GetForm(ctx).(*forms.GrantApplicationForm)
 	if ctx.Session.Get("client_id") != form.ClientID || ctx.Session.Get("state") != form.State ||
 		ctx.Session.Get("redirect_uri") != form.RedirectURI {
 		ctx.Error(http.StatusBadRequest)
@@ -391,7 +391,7 @@ func GrantApplicationOAuth(ctx *context.Context) {
 
 // AccessTokenOAuth manages all access token requests by the client
 func AccessTokenOAuth(ctx *context.Context) {
-	form := *web.GetForm(ctx).(*auth.AccessTokenForm)
+	form := *web.GetForm(ctx).(*forms.AccessTokenForm)
 	if form.ClientID == "" {
 		authHeader := ctx.Req.Header.Get("Authorization")
 		authContent := strings.SplitN(authHeader, " ", 2)
@@ -431,7 +431,7 @@ func AccessTokenOAuth(ctx *context.Context) {
 	}
 }
 
-func handleRefreshToken(ctx *context.Context, form auth.AccessTokenForm) {
+func handleRefreshToken(ctx *context.Context, form forms.AccessTokenForm) {
 	token, err := models.ParseOAuth2Token(form.RefreshToken)
 	if err != nil {
 		handleAccessTokenError(ctx, AccessTokenError{
@@ -467,7 +467,7 @@ func handleRefreshToken(ctx *context.Context, form auth.AccessTokenForm) {
 	ctx.JSON(http.StatusOK, accessToken)
 }
 
-func handleAuthorizationCode(ctx *context.Context, form auth.AccessTokenForm) {
+func handleAuthorizationCode(ctx *context.Context, form forms.AccessTokenForm) {
 	app, err := models.GetOAuth2ApplicationByClientID(form.ClientID)
 	if err != nil {
 		handleAccessTokenError(ctx, AccessTokenError{
diff --git a/routers/user/setting/account.go b/routers/user/setting/account.go
index 2b2804b53b..e12d63ee02 100644
--- a/routers/user/setting/account.go
+++ b/routers/user/setting/account.go
@@ -13,12 +13,12 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/password"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/timeutil"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 	"code.gitea.io/gitea/services/mailer"
 )
 
@@ -39,7 +39,7 @@ func Account(ctx *context.Context) {
 
 // AccountPost response for change user's password
 func AccountPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.ChangePasswordForm)
+	form := web.GetForm(ctx).(*forms.ChangePasswordForm)
 	ctx.Data["Title"] = ctx.Tr("settings")
 	ctx.Data["PageIsSettingsAccount"] = true
 
@@ -84,7 +84,7 @@ func AccountPost(ctx *context.Context) {
 
 // EmailPost response for change user's email
 func EmailPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.AddEmailForm)
+	form := web.GetForm(ctx).(*forms.AddEmailForm)
 	ctx.Data["Title"] = ctx.Tr("settings")
 	ctx.Data["PageIsSettingsAccount"] = true
 
@@ -257,7 +257,7 @@ func DeleteAccount(ctx *context.Context) {
 
 // UpdateUIThemePost is used to update users' specific theme
 func UpdateUIThemePost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.UpdateThemeForm)
+	form := web.GetForm(ctx).(*forms.UpdateThemeForm)
 	ctx.Data["Title"] = ctx.Tr("settings")
 	ctx.Data["PageIsSettingsAccount"] = true
 
diff --git a/routers/user/setting/account_test.go b/routers/user/setting/account_test.go
index 0e7e147b8b..25b68da762 100644
--- a/routers/user/setting/account_test.go
+++ b/routers/user/setting/account_test.go
@@ -9,10 +9,10 @@ import (
 	"testing"
 
 	"code.gitea.io/gitea/models"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/test"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 
 	"github.com/stretchr/testify/assert"
 )
@@ -86,7 +86,7 @@ func TestChangePassword(t *testing.T) {
 		test.LoadUser(t, ctx, 2)
 		test.LoadRepo(t, ctx, 1)
 
-		web.SetForm(ctx, &auth.ChangePasswordForm{
+		web.SetForm(ctx, &forms.ChangePasswordForm{
 			OldPassword: req.OldPassword,
 			Password:    req.NewPassword,
 			Retype:      req.Retype,
diff --git a/routers/user/setting/applications.go b/routers/user/setting/applications.go
index 367f2b38c1..4161efdea4 100644
--- a/routers/user/setting/applications.go
+++ b/routers/user/setting/applications.go
@@ -11,9 +11,9 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 )
 
 const (
@@ -32,7 +32,7 @@ func Applications(ctx *context.Context) {
 
 // ApplicationsPost response for add user's access token
 func ApplicationsPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.NewAccessTokenForm)
+	form := web.GetForm(ctx).(*forms.NewAccessTokenForm)
 	ctx.Data["Title"] = ctx.Tr("settings")
 	ctx.Data["PageIsSettingsApplications"] = true
 
diff --git a/routers/user/setting/keys.go b/routers/user/setting/keys.go
index 98b7b74137..e56a33afcb 100644
--- a/routers/user/setting/keys.go
+++ b/routers/user/setting/keys.go
@@ -11,9 +11,9 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 )
 
 const (
@@ -35,7 +35,7 @@ func Keys(ctx *context.Context) {
 
 // KeysPost response for change user's SSH/GPG keys
 func KeysPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.AddKeyForm)
+	form := web.GetForm(ctx).(*forms.AddKeyForm)
 	ctx.Data["Title"] = ctx.Tr("settings")
 	ctx.Data["PageIsSettingsKeys"] = true
 	ctx.Data["DisableSSH"] = setting.SSH.Disabled
diff --git a/routers/user/setting/oauth2.go b/routers/user/setting/oauth2.go
index a12f4dc1ba..c8db6e87f2 100644
--- a/routers/user/setting/oauth2.go
+++ b/routers/user/setting/oauth2.go
@@ -11,10 +11,10 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 )
 
 const (
@@ -23,7 +23,7 @@ const (
 
 // OAuthApplicationsPost response for adding a oauth2 application
 func OAuthApplicationsPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.EditOAuth2ApplicationForm)
+	form := web.GetForm(ctx).(*forms.EditOAuth2ApplicationForm)
 	ctx.Data["Title"] = ctx.Tr("settings")
 	ctx.Data["PageIsSettingsApplications"] = true
 
@@ -55,7 +55,7 @@ func OAuthApplicationsPost(ctx *context.Context) {
 
 // OAuthApplicationsEdit response for editing oauth2 application
 func OAuthApplicationsEdit(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.EditOAuth2ApplicationForm)
+	form := web.GetForm(ctx).(*forms.EditOAuth2ApplicationForm)
 	ctx.Data["Title"] = ctx.Tr("settings")
 	ctx.Data["PageIsSettingsApplications"] = true
 
diff --git a/routers/user/setting/profile.go b/routers/user/setting/profile.go
index c04428261a..0bc2b4ee36 100644
--- a/routers/user/setting/profile.go
+++ b/routers/user/setting/profile.go
@@ -17,12 +17,12 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/util"
 	"code.gitea.io/gitea/modules/web"
 	"code.gitea.io/gitea/modules/web/middleware"
+	"code.gitea.io/gitea/services/forms"
 
 	"github.com/unknwon/i18n"
 )
@@ -75,7 +75,7 @@ func HandleUsernameChange(ctx *context.Context, user *models.User, newName strin
 
 // ProfilePost response for change user's profile
 func ProfilePost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.UpdateProfileForm)
+	form := web.GetForm(ctx).(*forms.UpdateProfileForm)
 	ctx.Data["Title"] = ctx.Tr("settings")
 	ctx.Data["PageIsSettingsProfile"] = true
 
@@ -127,8 +127,8 @@ func ProfilePost(ctx *context.Context) {
 
 // UpdateAvatarSetting update user's avatar
 // FIXME: limit size.
-func UpdateAvatarSetting(ctx *context.Context, form *auth.AvatarForm, ctxUser *models.User) error {
-	ctxUser.UseCustomAvatar = form.Source == auth.AvatarLocal
+func UpdateAvatarSetting(ctx *context.Context, form *forms.AvatarForm, ctxUser *models.User) error {
+	ctxUser.UseCustomAvatar = form.Source == forms.AvatarLocal
 	if len(form.Gravatar) > 0 {
 		if form.Avatar != nil {
 			ctxUser.Avatar = base.EncodeMD5(form.Gravatar)
@@ -176,7 +176,7 @@ func UpdateAvatarSetting(ctx *context.Context, form *auth.AvatarForm, ctxUser *m
 
 // AvatarPost response for change user's avatar request
 func AvatarPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.AvatarForm)
+	form := web.GetForm(ctx).(*forms.AvatarForm)
 	if err := UpdateAvatarSetting(ctx, form, ctx.User); err != nil {
 		ctx.Flash.Error(err.Error())
 	} else {
diff --git a/routers/user/setting/security_openid.go b/routers/user/setting/security_openid.go
index c5d106e990..74dba12825 100644
--- a/routers/user/setting/security_openid.go
+++ b/routers/user/setting/security_openid.go
@@ -10,15 +10,15 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/auth/openid"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 )
 
 // OpenIDPost response for change user's openid
 func OpenIDPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.AddOpenIDForm)
+	form := web.GetForm(ctx).(*forms.AddOpenIDForm)
 	ctx.Data["Title"] = ctx.Tr("settings")
 	ctx.Data["PageIsSettingsSecurity"] = true
 
@@ -81,7 +81,7 @@ func settingsOpenIDVerify(ctx *context.Context) {
 
 	id, err := openid.Verify(fullURL)
 	if err != nil {
-		ctx.RenderWithErr(err.Error(), tplSettingsSecurity, &auth.AddOpenIDForm{
+		ctx.RenderWithErr(err.Error(), tplSettingsSecurity, &forms.AddOpenIDForm{
 			Openid: id,
 		})
 		return
@@ -92,7 +92,7 @@ func settingsOpenIDVerify(ctx *context.Context) {
 	oid := &models.UserOpenID{UID: ctx.User.ID, URI: id}
 	if err = models.AddUserOpenID(oid); err != nil {
 		if models.IsErrOpenIDAlreadyUsed(err) {
-			ctx.RenderWithErr(ctx.Tr("form.openid_been_used", id), tplSettingsSecurity, &auth.AddOpenIDForm{Openid: id})
+			ctx.RenderWithErr(ctx.Tr("form.openid_been_used", id), tplSettingsSecurity, &forms.AddOpenIDForm{Openid: id})
 			return
 		}
 		ctx.ServerError("AddUserOpenID", err)
diff --git a/routers/user/setting/security_twofa.go b/routers/user/setting/security_twofa.go
index a830495f54..7b08a05939 100644
--- a/routers/user/setting/security_twofa.go
+++ b/routers/user/setting/security_twofa.go
@@ -15,10 +15,10 @@ import (
 
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 
 	"github.com/pquerna/otp"
 	"github.com/pquerna/otp/totp"
@@ -168,7 +168,7 @@ func EnrollTwoFactor(ctx *context.Context) {
 
 // EnrollTwoFactorPost handles enrolling the user into 2FA.
 func EnrollTwoFactorPost(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.TwoFactorAuthForm)
+	form := web.GetForm(ctx).(*forms.TwoFactorAuthForm)
 	ctx.Data["Title"] = ctx.Tr("settings")
 	ctx.Data["PageIsSettingsSecurity"] = true
 
diff --git a/routers/user/setting/security_u2f.go b/routers/user/setting/security_u2f.go
index 040af34b5b..f9e35549fb 100644
--- a/routers/user/setting/security_u2f.go
+++ b/routers/user/setting/security_u2f.go
@@ -10,17 +10,17 @@ import (
 
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/context"
-	auth "code.gitea.io/gitea/modules/forms"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/web"
+	"code.gitea.io/gitea/services/forms"
 
 	"github.com/tstranex/u2f"
 )
 
 // U2FRegister initializes the u2f registration procedure
 func U2FRegister(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.U2FRegistrationForm)
+	form := web.GetForm(ctx).(*forms.U2FRegistrationForm)
 	if form.Name == "" {
 		ctx.Error(http.StatusConflict)
 		return
@@ -87,7 +87,7 @@ func U2FRegisterPost(ctx *context.Context) {
 
 // U2FDelete deletes an security key by id
 func U2FDelete(ctx *context.Context) {
-	form := web.GetForm(ctx).(*auth.U2FDeleteForm)
+	form := web.GetForm(ctx).(*forms.U2FDeleteForm)
 	reg, err := models.GetU2FRegistrationByID(form.ID)
 	if err != nil {
 		if models.IsErrU2FRegistrationNotExist(err) {
diff --git a/modules/forms/admin.go b/services/forms/admin.go
similarity index 100%
rename from modules/forms/admin.go
rename to services/forms/admin.go
diff --git a/modules/forms/auth_form.go b/services/forms/auth_form.go
similarity index 100%
rename from modules/forms/auth_form.go
rename to services/forms/auth_form.go
diff --git a/modules/forms/org.go b/services/forms/org.go
similarity index 100%
rename from modules/forms/org.go
rename to services/forms/org.go
diff --git a/modules/forms/repo_branch_form.go b/services/forms/repo_branch_form.go
similarity index 100%
rename from modules/forms/repo_branch_form.go
rename to services/forms/repo_branch_form.go
diff --git a/modules/forms/repo_form.go b/services/forms/repo_form.go
similarity index 100%
rename from modules/forms/repo_form.go
rename to services/forms/repo_form.go
diff --git a/modules/forms/repo_form_test.go b/services/forms/repo_form_test.go
similarity index 100%
rename from modules/forms/repo_form_test.go
rename to services/forms/repo_form_test.go
diff --git a/modules/forms/user_form.go b/services/forms/user_form.go
similarity index 100%
rename from modules/forms/user_form.go
rename to services/forms/user_form.go
diff --git a/modules/forms/user_form_auth_openid.go b/services/forms/user_form_auth_openid.go
similarity index 100%
rename from modules/forms/user_form_auth_openid.go
rename to services/forms/user_form_auth_openid.go
diff --git a/modules/forms/user_form_test.go b/services/forms/user_form_test.go
similarity index 100%
rename from modules/forms/user_form_test.go
rename to services/forms/user_form_test.go
diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl
index 10f016f4f4..c5a13a08f0 100644
--- a/templates/swagger/v1_json.tmpl
+++ b/templates/swagger/v1_json.tmpl
@@ -14630,7 +14630,7 @@
         }
       },
       "x-go-name": "MergePullRequestForm",
-      "x-go-package": "code.gitea.io/gitea/modules/forms"
+      "x-go-package": "code.gitea.io/gitea/services/forms"
     },
     "MigrateRepoForm": {
       "description": "MigrateRepoForm form for migrating repository\nthis is used to interact with web ui",
@@ -14710,7 +14710,7 @@
           "x-go-name": "Wiki"
         }
       },
-      "x-go-package": "code.gitea.io/gitea/modules/forms"
+      "x-go-package": "code.gitea.io/gitea/services/forms"
     },
     "MigrateRepoOptions": {
       "description": "MigrateRepoOptions options for migrating repository's\nthis is used to interact with api v1",