diff --git a/lib/gitlab/auth/auth_finders.rb b/lib/gitlab/auth/auth_finders.rb
index 4f1006503da960c52b56a450ff34d188778ed1c1..383b330ccdd67c96b486b375273eb8624f908655 100644
--- a/lib/gitlab/auth/auth_finders.rb
+++ b/lib/gitlab/auth/auth_finders.rb
@@ -299,6 +299,11 @@ def find_personal_access_token
         token = extract_personal_access_token
         return unless token
 
+        # The runner sends the job token for PUT /api/jobs/:id in the PRIVATE-TOKEN header
+        # and the token JSON parameter. Ignore this personal access token so
+        # that the job token can be authenticated.
+        return if api_request? && token.start_with?(::Ci::Build::TOKEN_PREFIX)
+
         # Expiration, revocation and scopes are verified in `validate_access_token!`
         PersonalAccessToken.find_by_token(token.to_s) || raise(UnauthorizedError)
       end
diff --git a/spec/lib/gitlab/auth/auth_finders_spec.rb b/spec/lib/gitlab/auth/auth_finders_spec.rb
index 35b36be0c09eaaa6ab73a5953a400b57872cf5ad..fd659d31cb76150f609a82bc93fce5cc3cbcb118 100644
--- a/spec/lib/gitlab/auth/auth_finders_spec.rb
+++ b/spec/lib/gitlab/auth/auth_finders_spec.rb
@@ -706,6 +706,14 @@ def set_bearer_token(token)
       expect(find_personal_access_token).to be_nil
     end
 
+    it 'returns nil if PAT looks like a build token' do
+      set_header('SCRIPT_NAME', nil)
+      set_header('PATH_INFO', '/api/v4/jobs/1')
+      set_header(described_class::PRIVATE_TOKEN_HEADER, "#{::Ci::Build::TOKEN_PREFIX}ABCD")
+
+      expect(find_personal_access_token).to be_nil
+    end
+
     it 'returns exception if invalid personal_access_token' do
       set_header(described_class::PRIVATE_TOKEN_HEADER, 'invalid_token')
 
diff --git a/spec/support/helpers/http_basic_auth_helpers.rb b/spec/support/helpers/http_basic_auth_helpers.rb
index 530007a9a7b6ad65787d0f92ce12b68f019172b5..b630be7a30e5f964d9365987b7029e7d4d1b2fb1 100644
--- a/spec/support/helpers/http_basic_auth_helpers.rb
+++ b/spec/support/helpers/http_basic_auth_helpers.rb
@@ -11,6 +11,10 @@ def job_basic_auth_header(job)
     basic_auth_header(::Gitlab::Auth::CI_JOB_USER, job.token)
   end
 
+  def job_token_auth_header(job)
+    { 'JOB-TOKEN' => job.token }
+  end
+
   def deploy_token_basic_auth_header(deploy_token)
     basic_auth_header(deploy_token.username, deploy_token.token)
   end
diff --git a/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb
index 2a7ee15aad254299dd19cbc4809eb9931627ebfb..20ee8b47a6b46838a800c973e1d1d0e992ddf47f 100644
--- a/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb
@@ -163,7 +163,7 @@
     end
 
     context 'with a job token for a completed job' do
-      let(:headers) { build_token_auth_header(job.token) }
+      let(:headers) { job_token_auth_header(job) }
 
       before do
         job.update!(status: :success)