From ab0bcddb13fc80bfb36f1eb8e939f62132e546cd Mon Sep 17 00:00:00 2001
From: KN4CK3R <admin@oldschoolhack.me>
Date: Tue, 4 Jan 2022 22:47:13 +0000
Subject: [PATCH 1/3] Show callback error message.

---
 options/locale/locale_en-US.ini |  1 +
 routers/web/auth/oauth.go       | 28 +++++++++++++++++++++++++++-
 2 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 9164d5ffdceda..e4ae560eec9a4 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -317,6 +317,7 @@ oauth_signup_submit = Complete Account
 oauth_signin_tab = Link to Existing Account
 oauth_signin_title = Sign In to Authorize Linked Account
 oauth_signin_submit = Link Account
+oauth_signin_error = Authorization failed: %s (%s)
 openid_connect_submit = Connect
 openid_connect_title = Connect to an existing account
 openid_connect_desc = The chosen OpenID URI is unknown. Associate it with a new account here.
diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go
index 9b22773d2f0d3..35ae44969ebb7 100644
--- a/routers/web/auth/oauth.go
+++ b/routers/web/auth/oauth.go
@@ -106,6 +106,16 @@ func (err AccessTokenError) Error() string {
 	return fmt.Sprintf("%s: %s", err.ErrorCode, err.ErrorDescription)
 }
 
+// errCallback represents a oauth2 callback error
+type errCallback struct {
+	Code        string
+	Description string
+}
+
+func (err errCallback) Error() string {
+	return err.Description
+}
+
 // TokenType specifies the kind of token
 type TokenType string
 
@@ -810,7 +820,6 @@ func SignInOAuthCallback(ctx *context.Context) {
 	}
 
 	u, gothUser, err := oAuth2UserLoginCallback(authSource, ctx.Req, ctx.Resp)
-
 	if err != nil {
 		if user_model.IsErrUserProhibitLogin(err) {
 			uplerr := err.(*user_model.ErrUserProhibitLogin)
@@ -819,6 +828,11 @@ func SignInOAuthCallback(ctx *context.Context) {
 			ctx.HTML(http.StatusOK, "user/auth/prohibit_login")
 			return
 		}
+		if callbackErr, ok := err.(errCallback); ok {
+			ctx.Flash.Error(ctx.Tr("auth.oauth_signin_error", callbackErr.Description, callbackErr.Code))
+			ctx.Redirect(setting.AppSubURL + "/user/login")
+			return
+		}
 		ctx.ServerError("UserSignIn", err)
 		return
 	}
@@ -1065,6 +1079,18 @@ func oAuth2UserLoginCallback(authSource *auth.Source, request *http.Request, res
 			log.Error("OAuth2 Provider %s returned too long a token. Current max: %d. Either increase the [OAuth2] MAX_TOKEN_LENGTH or reduce the information returned from the OAuth2 provider", authSource.Name, setting.OAuth2.MaxTokenLength)
 			err = fmt.Errorf("OAuth2 Provider %s returned too long a token. Current max: %d. Either increase the [OAuth2] MAX_TOKEN_LENGTH or reduce the information returned from the OAuth2 provider", authSource.Name, setting.OAuth2.MaxTokenLength)
 		}
+		// goth does not provide the original error message
+		// https://github.com/markbates/goth/issues/348
+		if strings.Contains(err.Error(), "server response missing access_token") || strings.Contains(err.Error(), "could not find a matching session for this request") {
+			errorCode := request.FormValue("error")
+			errorDescription := request.FormValue("error_description")
+			if errorCode != "" || errorDescription != "" {
+				return nil, goth.User{}, errCallback{
+					Code: errorCode,
+					Description: errorDescription,
+				}
+			}
+		}
 		return nil, goth.User{}, err
 	}
 

From f1ab592592b77350c24ff381b0c6061defdc1f2f Mon Sep 17 00:00:00 2001
From: KN4CK3R <admin@oldschoolhack.me>
Date: Tue, 4 Jan 2022 22:52:56 +0000
Subject: [PATCH 2/3] lint

---
 routers/web/auth/oauth.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go
index 35ae44969ebb7..c315dce01b4a3 100644
--- a/routers/web/auth/oauth.go
+++ b/routers/web/auth/oauth.go
@@ -1086,7 +1086,7 @@ func oAuth2UserLoginCallback(authSource *auth.Source, request *http.Request, res
 			errorDescription := request.FormValue("error_description")
 			if errorCode != "" || errorDescription != "" {
 				return nil, goth.User{}, errCallback{
-					Code: errorCode,
+					Code:        errorCode,
 					Description: errorDescription,
 				}
 			}

From 955152be49c2a4af2c8dbb435b2ef22c76cd1605 Mon Sep 17 00:00:00 2001
From: KN4CK3R <admin@oldschoolhack.me>
Date: Thu, 6 Jan 2022 16:34:01 +0000
Subject: [PATCH 3/3] Use error code to display a message.

---
 options/locale/locale_en-US.ini |  4 +++-
 routers/web/auth/oauth.go       | 10 +++++++++-
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 7dd9654372fe8..a49d3f657ce9b 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -317,7 +317,9 @@ oauth_signup_submit = Complete Account
 oauth_signin_tab = Link to Existing Account
 oauth_signin_title = Sign In to Authorize Linked Account
 oauth_signin_submit = Link Account
-oauth_signin_error = Authorization failed: %s (%s)
+oauth.signin.error = There was an error processing the authorization request. If this error persists, please contact the site administrator.
+oauth.signin.error.access_denied = The authorization request was denied.
+oauth.signin.error.temporarily_unavailable = Authorization failed because the authentication server is temporarily unavailable. Please try again later.
 openid_connect_submit = Connect
 openid_connect_title = Connect to an existing account
 openid_connect_desc = The chosen OpenID URI is unknown. Associate it with a new account here.
diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go
index c315dce01b4a3..d20bf97f3cbf6 100644
--- a/routers/web/auth/oauth.go
+++ b/routers/web/auth/oauth.go
@@ -829,7 +829,15 @@ func SignInOAuthCallback(ctx *context.Context) {
 			return
 		}
 		if callbackErr, ok := err.(errCallback); ok {
-			ctx.Flash.Error(ctx.Tr("auth.oauth_signin_error", callbackErr.Description, callbackErr.Code))
+			log.Info("Failed OAuth callback: (%v) %v", callbackErr.Code, callbackErr.Description)
+			switch callbackErr.Code {
+			case "access_denied":
+				ctx.Flash.Error(ctx.Tr("auth.oauth.signin.error.access_denied"))
+			case "temporarily_unavailable":
+				ctx.Flash.Error(ctx.Tr("auth.oauth.signin.error.temporarily_unavailable"))
+			default:
+				ctx.Flash.Error(ctx.Tr("auth.oauth.signin.error"))
+			}
 			ctx.Redirect(setting.AppSubURL + "/user/login")
 			return
 		}