diff --git a/tests/integration/integration_test.go b/tests/integration/integration_test.go
index 94ee33bf5b..f6d028df2c 100644
--- a/tests/integration/integration_test.go
+++ b/tests/integration/integration_test.go
@@ -39,6 +39,8 @@ import (
 	"code.gitea.io/gitea/tests"
 
 	"github.com/PuerkitoBio/goquery"
+	"github.com/markbates/goth"
+	"github.com/markbates/goth/gothic"
 	goth_gitlab "github.com/markbates/goth/providers/gitlab"
 	"github.com/stretchr/testify/assert"
 	"github.com/xeipuuv/gojsonschema"
@@ -232,6 +234,14 @@ func getUserToken(t testing.TB, userName string, scope ...auth.AccessTokenScope)
 	return getTokenForLoggedInUser(t, loginUser(t, userName), scope...)
 }
 
+func mockCompleteUserAuth(mock func(res http.ResponseWriter, req *http.Request) (goth.User, error)) func() {
+	old := gothic.CompleteUserAuth
+	gothic.CompleteUserAuth = mock
+	return func() {
+		gothic.CompleteUserAuth = old
+	}
+}
+
 func addAuthSource(t *testing.T, payload map[string]string) *auth.Source {
 	session := loginUser(t, "user1")
 	payload["_csrf"] = GetCSRF(t, session, "/admin/auths/new")
diff --git a/tests/integration/oauth_test.go b/tests/integration/oauth_test.go
index e9b69f5f14..4a00d73a02 100644
--- a/tests/integration/oauth_test.go
+++ b/tests/integration/oauth_test.go
@@ -5,15 +5,22 @@ package integration
 
 import (
 	"bytes"
+	"context"
+	"fmt"
 	"io"
 	"net/http"
 	"testing"
 
+	auth_model "code.gitea.io/gitea/models/auth"
+	"code.gitea.io/gitea/models/unittest"
+	user_model "code.gitea.io/gitea/models/user"
 	"code.gitea.io/gitea/modules/json"
 	"code.gitea.io/gitea/modules/setting"
+	"code.gitea.io/gitea/modules/test"
 	"code.gitea.io/gitea/routers/web/auth"
 	"code.gitea.io/gitea/tests"
 
+	"github.com/markbates/goth"
 	"github.com/stretchr/testify/assert"
 )
 
@@ -419,3 +426,46 @@ func TestRefreshTokenInvalidation(t *testing.T) {
 	assert.Equal(t, "unauthorized_client", string(parsedError.ErrorCode))
 	assert.Equal(t, "token was already used", parsedError.ErrorDescription)
 }
+
+func TestSignInOAuthCallbackSignIn(t *testing.T) {
+	defer tests.PrepareTestEnv(t)()
+
+	//
+	// OAuth2 authentication source GitLab
+	//
+	gitlabName := "gitlab"
+	gitlab := addAuthSource(t, authSourcePayloadGitLabCustom(gitlabName))
+
+	//
+	// Create a user as if it had been previously been created by the GitLab
+	// authentication source.
+	//
+	userGitLabUserID := "5678"
+	userGitLab := &user_model.User{
+		Name:        "gitlabuser",
+		Email:       "gitlabuser@example.com",
+		Passwd:      "gitlabuserpassword",
+		Type:        user_model.UserTypeIndividual,
+		LoginType:   auth_model.OAuth2,
+		LoginSource: gitlab.ID,
+		LoginName:   userGitLabUserID,
+	}
+	defer createUser(context.Background(), t, userGitLab)()
+
+	//
+	// A request for user information sent to Goth will return a
+	// goth.User exactly matching the user created above.
+	//
+	defer mockCompleteUserAuth(func(res http.ResponseWriter, req *http.Request) (goth.User, error) {
+		return goth.User{
+			Provider: gitlabName,
+			UserID:   userGitLabUserID,
+			Email:    userGitLab.Email,
+		}, nil
+	})()
+	req := NewRequest(t, "GET", fmt.Sprintf("/user/oauth2/%s/callback?code=XYZ&state=XYZ", gitlabName))
+	resp := MakeRequest(t, req, http.StatusSeeOther)
+	assert.Equal(t, test.RedirectURL(resp), "/")
+	userAfterLogin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userGitLab.ID})
+	assert.Greater(t, userAfterLogin.LastLoginUnix, userGitLab.LastLoginUnix)
+}