diff --git a/server/handlers.go b/server/handlers.go
index df348f9a82ca95ad3d4f062b64a60551d4d4e7ba..3c402a07bc6efb31d01c288044f18c7b797b2ad8 100644
--- a/server/handlers.go
+++ b/server/handlers.go
@@ -805,6 +805,11 @@ func (s *Server) handleAuthCode(w http.ResponseWriter, r *http.Request, client s
 	code := r.PostFormValue("code")
 	redirectURI := r.PostFormValue("redirect_uri")
 
+	if code == "" {
+		s.tokenErrHelper(w, errInvalidRequest, `Required param: code.`, http.StatusBadRequest)
+		return
+	}
+
 	authCode, err := s.storage.GetAuthCode(code)
 	if err != nil || s.now().After(authCode.Expiry) || authCode.ClientID != client.ID {
 		if err != storage.ErrNotFound {
diff --git a/server/handlers_test.go b/server/handlers_test.go
index 07af8b950c9e6317019e3edaa63d103cf8f6741a..4ca182f28a029c35528936631e2ee64c7adec219 100644
--- a/server/handlers_test.go
+++ b/server/handlers_test.go
@@ -208,69 +208,100 @@ func TestConnectorLoginDoesNotAllowToChangeConnectorForAuthRequest(t *testing.T)
 	}
 }
 
-// TestHandleCodeReuse checks that it is forbidden to use same code twice
-func TestHandleCodeReuse(t *testing.T) {
-	ctx, cancel := context.WithCancel(context.Background())
-	defer cancel()
-
-	httpServer, s := newTestServer(ctx, t, func(c *Config) { c.Issuer += "/non-root-path" })
-	defer httpServer.Close()
-
-	p, err := oidc.NewProvider(ctx, httpServer.URL)
-	require.NoError(t, err)
+// TestHandleAuthCode checks that it is forbidden to use same code twice
+func TestHandleAuthCode(t *testing.T) {
+	tests := []struct {
+		name       string
+		handleCode func(*testing.T, context.Context, *oauth2.Config, string)
+	}{
+		{
+			name: "Code Reuse should return invalid_grant",
+			handleCode: func(t *testing.T, ctx context.Context, oauth2Config *oauth2.Config, code string) {
+				_, err := oauth2Config.Exchange(ctx, code)
+				require.NoError(t, err)
+
+				_, err = oauth2Config.Exchange(ctx, code)
+				require.Error(t, err)
+
+				oauth2Err, ok := err.(*oauth2.RetrieveError)
+				require.True(t, ok)
+
+				var errResponse struct{ Error string }
+				err = json.Unmarshal(oauth2Err.Body, &errResponse)
+				require.NoError(t, err)
+
+				// invalid_grant must be returned for invalid values
+				// https://tools.ietf.org/html/rfc6749#section-5.2
+				require.Equal(t, errInvalidGrant, errResponse.Error)
+			},
+		},
+		{
+			name: "No Code should return invalid_request",
+			handleCode: func(t *testing.T, ctx context.Context, oauth2Config *oauth2.Config, _ string) {
+				_, err := oauth2Config.Exchange(ctx, "")
+				require.Error(t, err)
+
+				oauth2Err, ok := err.(*oauth2.RetrieveError)
+				require.True(t, ok)
+
+				var errResponse struct{ Error string }
+				err = json.Unmarshal(oauth2Err.Body, &errResponse)
+				require.NoError(t, err)
+
+				require.Equal(t, errInvalidRequest, errResponse.Error)
+			},
+		},
+	}
 
-	var oauth2Client oauth2Client
-	oauth2Client.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		if r.URL.Path != "/callback" {
-			http.Redirect(w, r, oauth2Client.config.AuthCodeURL(""), http.StatusSeeOther)
-			return
-		}
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			ctx, cancel := context.WithCancel(context.Background())
+			defer cancel()
 
-		q := r.URL.Query()
-		require.Equal(t, q.Get("error"), "", q.Get("error_description"))
+			httpServer, s := newTestServer(ctx, t, func(c *Config) { c.Issuer += "/non-root-path" })
+			defer httpServer.Close()
 
-		if code := q.Get("code"); code != "" {
-			_, err := oauth2Client.config.Exchange(ctx, code)
+			p, err := oidc.NewProvider(ctx, httpServer.URL)
 			require.NoError(t, err)
 
-			_, err = oauth2Client.config.Exchange(ctx, code)
-			require.Error(t, err)
-
-			oauth2Err, ok := err.(*oauth2.RetrieveError)
-			require.True(t, ok)
-
-			var errResponse struct{ Error string }
-			err = json.Unmarshal(oauth2Err.Body, &errResponse)
+			var oauth2Client oauth2Client
+			oauth2Client.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+				if r.URL.Path != "/callback" {
+					http.Redirect(w, r, oauth2Client.config.AuthCodeURL(""), http.StatusSeeOther)
+					return
+				}
+
+				q := r.URL.Query()
+				require.Equal(t, q.Get("error"), "", q.Get("error_description"))
+
+				code := q.Get("code")
+				tc.handleCode(t, ctx, oauth2Client.config, code)
+
+				w.WriteHeader(http.StatusOK)
+			}))
+			defer oauth2Client.server.Close()
+
+			redirectURL := oauth2Client.server.URL + "/callback"
+			client := storage.Client{
+				ID:           "testclient",
+				Secret:       "testclientsecret",
+				RedirectURIs: []string{redirectURL},
+			}
+			err = s.storage.CreateClient(client)
 			require.NoError(t, err)
 
-			// invalid_grant must be returned for invalid values
-			// https://tools.ietf.org/html/rfc6749#section-5.2
-			require.Equal(t, errInvalidGrant, errResponse.Error)
-		}
+			oauth2Client.config = &oauth2.Config{
+				ClientID:     client.ID,
+				ClientSecret: client.Secret,
+				Endpoint:     p.Endpoint(),
+				Scopes:       []string{oidc.ScopeOpenID, "email", "offline_access"},
+				RedirectURL:  redirectURL,
+			}
 
-		w.WriteHeader(http.StatusOK)
-	}))
-	defer oauth2Client.server.Close()
+			resp, err := http.Get(oauth2Client.server.URL + "/login")
+			require.NoError(t, err)
 
-	redirectURL := oauth2Client.server.URL + "/callback"
-	client := storage.Client{
-		ID:           "testclient",
-		Secret:       "testclientsecret",
-		RedirectURIs: []string{redirectURL},
-	}
-	err = s.storage.CreateClient(client)
-	require.NoError(t, err)
-
-	oauth2Client.config = &oauth2.Config{
-		ClientID:     client.ID,
-		ClientSecret: client.Secret,
-		Endpoint:     p.Endpoint(),
-		Scopes:       []string{oidc.ScopeOpenID, "email", "offline_access"},
-		RedirectURL:  redirectURL,
+			resp.Body.Close()
+		})
 	}
-
-	resp, err := http.Get(oauth2Client.server.URL + "/login")
-	require.NoError(t, err)
-
-	resp.Body.Close()
 }