diff --git a/changelogs/unreleased/25482-fix-api-sudo.yml b/changelogs/unreleased/25482-fix-api-sudo.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3b23bfd3a210c88e81548e99153921b925e33aa6
--- /dev/null
+++ b/changelogs/unreleased/25482-fix-api-sudo.yml
@@ -0,0 +1,4 @@
+---
+title: 'API: Memoize the current_user so that the sudo can work properly'
+merge_request: 8017
+author: 
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 8b0f8deadfa6d7d77104f0302418841cc0993957..2041f0dac6b0ad23f872e0edd120795aa16a682c 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -7,67 +7,23 @@ module API
     SUDO_HEADER = "HTTP_SUDO"
     SUDO_PARAM = :sudo
 
-    def private_token
-      params[PRIVATE_TOKEN_PARAM] || env[PRIVATE_TOKEN_HEADER]
-    end
-
-    def warden
-      env['warden']
-    end
-
-    # Check the Rails session for valid authentication details
-    #
-    # Until CSRF protection is added to the API, disallow this method for
-    # state-changing endpoints
-    def find_user_from_warden
-      warden.try(:authenticate) if %w[GET HEAD].include?(env['REQUEST_METHOD'])
-    end
-
     def declared_params(options = {})
       options = { include_parent_namespaces: false }.merge(options)
       declared(params, options).to_h.symbolize_keys
     end
 
-    def find_user_by_private_token
-      token = private_token
-      return nil unless token.present?
-
-      User.find_by_authentication_token(token) || User.find_by_personal_access_token(token)
-    end
-
     def current_user
-      @current_user ||= find_user_by_private_token
-      @current_user ||= doorkeeper_guard
-      @current_user ||= find_user_from_warden
-
-      unless @current_user && Gitlab::UserAccess.new(@current_user).allowed?
-        return nil
-      end
-
-      identifier = sudo_identifier
+      return @current_user if defined?(@current_user)
 
-      if identifier
-        # We check for private_token because we cannot allow PAT to be used
-        forbidden!('Must be admin to use sudo') unless @current_user.is_admin?
-        forbidden!('Private token must be specified in order to use sudo') unless private_token_used?
+      @current_user = initial_current_user
 
-        @impersonator = @current_user
-        @current_user = User.by_username_or_id(identifier)
-        not_found!("No user id or username for: #{identifier}") if @current_user.nil?
-      end
+      sudo!
 
       @current_user
     end
 
-    def sudo_identifier
-      identifier ||= params[SUDO_PARAM] || env[SUDO_HEADER]
-
-      # Regex for integers
-      if !!(identifier =~ /\A[0-9]+\z/)
-        identifier.to_i
-      else
-        identifier
-      end
+    def sudo?
+      initial_current_user != current_user
     end
 
     def user_project
@@ -354,6 +310,79 @@ module API
 
     private
 
+    def private_token
+      params[PRIVATE_TOKEN_PARAM] || env[PRIVATE_TOKEN_HEADER]
+    end
+
+    def warden
+      env['warden']
+    end
+
+    # Check the Rails session for valid authentication details
+    #
+    # Until CSRF protection is added to the API, disallow this method for
+    # state-changing endpoints
+    def find_user_from_warden
+      warden.try(:authenticate) if %w[GET HEAD].include?(env['REQUEST_METHOD'])
+    end
+
+    def find_user_by_private_token
+      token = private_token
+      return nil unless token.present?
+
+      User.find_by_authentication_token(token) || User.find_by_personal_access_token(token)
+    end
+
+    def initial_current_user
+      return @initial_current_user if defined?(@initial_current_user)
+
+      @initial_current_user ||= find_user_by_private_token
+      @initial_current_user ||= doorkeeper_guard
+      @initial_current_user ||= find_user_from_warden
+
+      unless @initial_current_user && Gitlab::UserAccess.new(@initial_current_user).allowed?
+        @initial_current_user = nil
+      end
+
+      @initial_current_user
+    end
+
+    def sudo!
+      return unless sudo_identifier
+      return unless initial_current_user.is_a?(User)
+
+      unless initial_current_user.is_admin?
+        forbidden!('Must be admin to use sudo')
+      end
+
+      # Only private tokens should be used for the SUDO feature
+      unless private_token == initial_current_user.private_token
+        forbidden!('Private token must be specified in order to use sudo')
+      end
+
+      sudoed_user = User.by_username_or_id(sudo_identifier)
+
+      if sudoed_user
+        @current_user = sudoed_user
+      else
+        not_found!("No user id or username for: #{sudo_identifier}")
+      end
+    end
+
+    def sudo_identifier
+      return @sudo_identifier if defined?(@sudo_identifier)
+
+      identifier ||= params[SUDO_PARAM] || env[SUDO_HEADER]
+
+      # Regex for integers
+      @sudo_identifier =
+        if !!(identifier =~ /\A[0-9]+\z/)
+          identifier.to_i
+        else
+          identifier
+        end
+    end
+
     def add_pagination_headers(paginated_data)
       header 'X-Total',       paginated_data.total_count.to_s
       header 'X-Total-Pages', paginated_data.total_pages.to_s
@@ -386,10 +415,6 @@ module API
       links.join(', ')
     end
 
-    def private_token_used?
-      private_token == @current_user.private_token
-    end
-
     def secret_token
       Gitlab::Shell.secret_token
     end
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 1dab799dd61e6fc2ba42d11f3b1193d8db7cd7c2..c7db2d7101715d324dcb8ba82c71a32e5a9dd9b0 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -353,7 +353,7 @@ module API
         success Entities::UserPublic
       end
       get do
-        present current_user, with: @impersonator ? Entities::UserWithPrivateToken : Entities::UserPublic
+        present current_user, with: sudo? ? Entities::UserWithPrivateToken : Entities::UserPublic
       end
 
       desc "Get the currently authenticated user's SSH keys" do
diff --git a/spec/requests/api/api_helpers_spec.rb b/spec/requests/api/helpers_spec.rb
similarity index 86%
rename from spec/requests/api/api_helpers_spec.rb
rename to spec/requests/api/helpers_spec.rb
index 3f34309f419c0ce4b5ed7042b79c29de6f082a12..573154f69b4d47fe5c72ca0bb83c69209f9b6a1a 100644
--- a/spec/requests/api/api_helpers_spec.rb
+++ b/spec/requests/api/helpers_spec.rb
@@ -2,7 +2,6 @@ require 'spec_helper'
 
 describe API::Helpers, api: true do
   include API::Helpers
-  include ApiHelpers
   include SentryHelper
 
   let(:user) { create(:user) }
@@ -13,17 +12,17 @@ describe API::Helpers, api: true do
   let(:env) { { 'REQUEST_METHOD' => 'GET' } }
   let(:request) { Rack::Request.new(env) }
 
-  def set_env(token_usr, identifier)
+  def set_env(user_or_token, identifier)
     clear_env
     clear_param
-    env[API::Helpers::PRIVATE_TOKEN_HEADER] = token_usr.private_token
+    env[API::Helpers::PRIVATE_TOKEN_HEADER] = user_or_token.respond_to?(:private_token) ? user_or_token.private_token : user_or_token
     env[API::Helpers::SUDO_HEADER] = identifier
   end
 
-  def set_param(token_usr, identifier)
+  def set_param(user_or_token, identifier)
     clear_env
     clear_param
-    params[API::Helpers::PRIVATE_TOKEN_PARAM] = token_usr.private_token
+    params[API::Helpers::PRIVATE_TOKEN_PARAM] = user_or_token.respond_to?(:private_token) ? user_or_token.private_token : user_or_token
     params[API::Helpers::SUDO_PARAM] = identifier
   end
 
@@ -163,6 +162,13 @@ describe API::Helpers, api: true do
               expect(current_user).to eq(user)
             end
 
+            it 'memoize the current_user: sudo permissions are not run against the sudoed user' do
+              set_env(admin, user.id)
+
+              expect(current_user).to eq(user)
+              expect(current_user).to eq(user)
+            end
+
             it 'handles sudo to oneself' do
               set_env(admin, admin.id)
 
@@ -294,33 +300,48 @@ describe API::Helpers, api: true do
     end
   end
 
-  describe '.sudo_identifier' do
-    it "returns integers when input is an int" do
-      set_env(admin, '123')
-      expect(sudo_identifier).to eq(123)
-      set_env(admin, '0001234567890')
-      expect(sudo_identifier).to eq(1234567890)
-
-      set_param(admin, '123')
-      expect(sudo_identifier).to eq(123)
-      set_param(admin, '0001234567890')
-      expect(sudo_identifier).to eq(1234567890)
+  describe '.sudo?' do
+    context 'when no sudo env or param is passed' do
+      before do
+        doorkeeper_guard_returns(nil)
+      end
+
+      it 'returns false' do
+        expect(sudo?).to be_falsy
+      end
     end
 
-    it "returns string when input is an is not an int" do
-      set_env(admin, '12.30')
-      expect(sudo_identifier).to eq("12.30")
-      set_env(admin, 'hello')
-      expect(sudo_identifier).to eq('hello')
-      set_env(admin, ' 123')
-      expect(sudo_identifier).to eq(' 123')
-
-      set_param(admin, '12.30')
-      expect(sudo_identifier).to eq("12.30")
-      set_param(admin, 'hello')
-      expect(sudo_identifier).to eq('hello')
-      set_param(admin, ' 123')
-      expect(sudo_identifier).to eq(' 123')
+    context 'when sudo env or param is passed', 'user is not an admin' do
+      before do
+        set_env(user, '123')
+      end
+
+      it 'returns an 403 Forbidden' do
+        expect { sudo? }.to raise_error '403 - {"message"=>"403 Forbidden  - Must be admin to use sudo"}'
+      end
+    end
+
+    context 'when sudo env or param is passed', 'user is admin' do
+      context 'personal access token is used' do
+        before do
+          personal_access_token = create(:personal_access_token, user: admin)
+          set_env(personal_access_token.token, user.id)
+        end
+
+        it 'returns an 403 Forbidden' do
+          expect { sudo? }.to raise_error '403 - {"message"=>"403 Forbidden  - Private token must be specified in order to use sudo"}'
+        end
+      end
+
+      context 'private access token is used' do
+        before do
+          set_env(admin.private_token, user.id)
+        end
+
+        it 'returns true' do
+          expect(sudo?).to be_truthy
+        end
+      end
     end
   end
 
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index c37dbfa0a3350bd5ada1a6d31ca08bf07e6f4ba3..9e317f3a7e91498abf37ebff32771bdcc972fdf5 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -651,13 +651,12 @@ describe API::Users, api: true  do
   end
 
   describe "GET /user" do
-    let(:personal_access_token) { create(:personal_access_token, user: user) }
-    let(:private_token) { user.private_token }
+    let(:personal_access_token) { create(:personal_access_token, user: user).token }
 
     context 'with regular user' do
       context 'with personal access token' do
         it 'returns 403 without private token when sudo is defined' do
-          get api("/user?private_token=#{personal_access_token.token}&sudo=#{user.id}")
+          get api("/user?private_token=#{personal_access_token}&sudo=123")
 
           expect(response).to have_http_status(403)
         end
@@ -665,7 +664,7 @@ describe API::Users, api: true  do
 
       context 'with private token' do
         it 'returns 403 without private token when sudo defined' do
-          get api("/user?private_token=#{private_token}&sudo=#{user.id}")
+          get api("/user?private_token=#{user.private_token}&sudo=123")
 
           expect(response).to have_http_status(403)
         end
@@ -676,40 +675,44 @@ describe API::Users, api: true  do
 
         expect(response).to have_http_status(200)
         expect(response).to match_response_schema('user/public')
+        expect(json_response['id']).to eq(user.id)
       end
     end
 
     context 'with admin' do
-      let(:user) { create(:admin) }
+      let(:admin_personal_access_token) { create(:personal_access_token, user: admin).token }
 
       context 'with personal access token' do
         it 'returns 403 without private token when sudo defined' do
-          get api("/user?private_token=#{personal_access_token.token}&sudo=#{user.id}")
+          get api("/user?private_token=#{admin_personal_access_token}&sudo=#{user.id}")
 
           expect(response).to have_http_status(403)
         end
 
-        it 'returns current user without private token when sudo not defined' do
-          get api("/user?private_token=#{personal_access_token.token}")
+        it 'returns initial current user without private token when sudo not defined' do
+          get api("/user?private_token=#{admin_personal_access_token}")
 
           expect(response).to have_http_status(200)
           expect(response).to match_response_schema('user/public')
+          expect(json_response['id']).to eq(admin.id)
         end
       end
 
       context 'with private token' do
-        it 'returns current user with private token when sudo defined' do
-          get api("/user?private_token=#{private_token}&sudo=#{user.id}")
+        it 'returns sudoed user with private token when sudo defined' do
+          get api("/user?private_token=#{admin.private_token}&sudo=#{user.id}")
 
           expect(response).to have_http_status(200)
           expect(response).to match_response_schema('user/login')
+          expect(json_response['id']).to eq(user.id)
         end
 
-        it 'returns current user without private token when sudo not defined' do
-          get api("/user?private_token=#{private_token}")
+        it 'returns initial current user without private token when sudo not defined' do
+          get api("/user?private_token=#{admin.private_token}")
 
           expect(response).to have_http_status(200)
           expect(response).to match_response_schema('user/public')
+          expect(json_response['id']).to eq(admin.id)
         end
       end
     end