diff --git a/app/models/container_registry/event.rb b/app/models/container_registry/event.rb
index 9f7724c052cf366f991ed870dd859c742198ddc0..57fa24abf06b91e6daa66aca4ca207a1024d3ea9 100644
--- a/app/models/container_registry/event.rb
+++ b/app/models/container_registry/event.rb
@@ -14,6 +14,7 @@ class Event
       personal_access_token
       build
       gitlab_or_ldap
+      deploy_token
     ].freeze
 
     TRACKABLE_ACTOR_EVENTS = %w[
@@ -39,7 +40,6 @@ def handle!
     end
 
     def track!
-      tracked_target = target_tag? ? :tag : :repository
       tracking_action = "#{action}_#{tracked_target}"
 
       if target_repository? && action_push? && !container_repository_exists?
@@ -58,6 +58,10 @@ def track!
 
     private
 
+    def tracked_target
+      target_tag? ? :tag : :repository
+    end
+
     def target_tag?
       # There is no clear indication in the event structure when we delete a top-level manifest
       # except existence of "tag" key
@@ -108,22 +112,51 @@ def usage_data_event_for(tracking_action)
       return unless originator
       return unless TRACKABLE_ACTOR_EVENTS.include?(tracking_action)
 
-      "#{EVENT_PREFIX}_#{tracking_action}_user"
+      "#{EVENT_PREFIX}_#{tracking_action}_#{originator_suffix}"
+    end
+
+    def originator
+      return unless ALLOWED_ACTOR_TYPES.include?(originator_type)
+
+      origin_id = get_origin_id(originator_type)
+      return unless origin_id
+
+      origin_class.find(origin_id)
+    end
+    strong_memoize_attr :originator
+
+    def originator_suffix
+      originator.is_a?(DeployToken) ? 'deploy_token' : 'user'
     end
 
     def originator_type
       event.dig('actor', 'user_type')
     end
 
-    def originator
-      return unless ALLOWED_ACTOR_TYPES.include?(originator_type)
+    def origin_class
+      deploy_token?(originator_type) ? DeployToken : User
+    end
 
-      username = event.dig('actor', 'name')
-      return unless username
+    def get_origin_id(originator_type)
+      encoded_user_jwt = event.dig('actor', 'user')
+      return unless encoded_user_jwt
 
-      strong_memoize(:originator) do
-        User.find_by_username(username)
-      end
+      key = deploy_token?(originator_type) ? 'deploy_token_id' : 'user_id'
+      user_info = decode_user_info(encoded_user_jwt)
+      user_info&.dig('user_info', key)
+    end
+
+    def decode_user_info(encoded_user_jwt)
+      registry_key_file = File.read(Gitlab.config.registry.key)
+      registry_key = OpenSSL::PKey::RSA.new(registry_key_file)
+
+      JSONWebToken::RSAToken.decode(encoded_user_jwt, registry_key).first
+    rescue Errno::ENOENT, JWT::VerificationError, JWT::DecodeError, JWT::ExpiredSignature, JWT::ImmatureSignature
+      nil
+    end
+
+    def deploy_token?(originator_type)
+      originator_type == 'deploy_token'
     end
 
     def manifest_delete_event?
diff --git a/config/metrics/counts_28d/20231227173838_i_container_registry_push_tag_deploy_token_monthly.yml b/config/metrics/counts_28d/20231227173838_i_container_registry_push_tag_deploy_token_monthly.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b4b2d8bb91e812430f18ed4b5ad840cc51ec657e
--- /dev/null
+++ b/config/metrics/counts_28d/20231227173838_i_container_registry_push_tag_deploy_token_monthly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.user_container_registry.i_container_registry_push_tag_deploy_token_monthly
+description: A monthly count of deploy tokens that have pushed a tag to the registry
+product_section: ops
+product_stage: package
+product_group: container_registry
+value_type: number
+status: active
+milestone: "16.9"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131966
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+  events:
+  - i_container_registry_push_tag_deploy_token
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20231227174251_i_container_registry_delete_tag_deploy_token_monthly.yml b/config/metrics/counts_28d/20231227174251_i_container_registry_delete_tag_deploy_token_monthly.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e2e2382d2398c732d9915851b99e93b2283482f1
--- /dev/null
+++ b/config/metrics/counts_28d/20231227174251_i_container_registry_delete_tag_deploy_token_monthly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.user_container_registry.i_container_registry_delete_tag_deploy_token_monthly
+description: A monthly count of deploy tokens that have deleted a tag from the registry
+product_section: ops
+product_stage: package
+product_group: container_registry
+value_type: number
+status: active
+milestone: "16.9"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131966
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+  events:
+  - i_container_registry_delete_tag_deploy_token
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20231227175541_i_container_registry_push_repository_deploy_token_monthly.yml b/config/metrics/counts_28d/20231227175541_i_container_registry_push_repository_deploy_token_monthly.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e5a0cc88b47113e5b7190bed6f530f8a28fb83b3
--- /dev/null
+++ b/config/metrics/counts_28d/20231227175541_i_container_registry_push_repository_deploy_token_monthly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.user_container_registry.i_container_registry_push_repository_deploy_token_monthly
+description: A monthly count of deploy tokens that have pushed a repository to the registry
+product_section: ops
+product_stage: package
+product_group: container_registry
+value_type: number
+status: active
+milestone: "16.9"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131966
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+  events:
+  - i_container_registry_push_repository_deploy_token
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20231227175706_i_container_registry_delete_repository_deploy_token_monthly.yml b/config/metrics/counts_28d/20231227175706_i_container_registry_delete_repository_deploy_token_monthly.yml
new file mode 100644
index 0000000000000000000000000000000000000000..f315cb6d7a61a39052cd1c59aac25eee7e51e068
--- /dev/null
+++ b/config/metrics/counts_28d/20231227175706_i_container_registry_delete_repository_deploy_token_monthly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.user_container_registry.i_container_registry_delete_repository_deploy_token_monthly
+description: A monthly count of deploy tokens that have deleted a repository from the registry
+product_section: ops
+product_stage: package
+product_group: container_registry
+value_type: number
+status: active
+milestone: "16.9"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131966
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+  events:
+  - i_container_registry_delete_repository_deploy_token
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20231227180108_i_container_registry_create_repository_deploy_token_monthly.yml b/config/metrics/counts_28d/20231227180108_i_container_registry_create_repository_deploy_token_monthly.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e27087d61d9dd077f77084e51fc6110660f33fa0
--- /dev/null
+++ b/config/metrics/counts_28d/20231227180108_i_container_registry_create_repository_deploy_token_monthly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.user_container_registry.i_container_registry_create_repository_deploy_token_monthly
+description: A monthly count of deploy tokens that have created a repository from the registry
+product_section: ops
+product_stage: package
+product_group: container_registry
+value_type: number
+status: active
+milestone: "16.9"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131966
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+  events:
+  - i_container_registry_create_repository_deploy_token
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_7d/20231223170002_i_container_registry_push_repository_deploy_token_weekly.yml b/config/metrics/counts_7d/20231223170002_i_container_registry_push_repository_deploy_token_weekly.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5e0fff110a65e9343450118fe0bdde91732952a6
--- /dev/null
+++ b/config/metrics/counts_7d/20231223170002_i_container_registry_push_repository_deploy_token_weekly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.user_container_registry.i_container_registry_push_repository_deploy_token_weekly
+description: A weekly count of deploy tokens that have pushed a repository to the registry
+product_section: ops
+product_stage: package
+product_group: container_registry
+value_type: number
+status: active
+milestone: "16.9"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131966
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+  events:
+  - i_container_registry_push_repository_deploy_token
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_7d/20231227165432_i_container_registry_push_tag_deploy_token_weekly.yml b/config/metrics/counts_7d/20231227165432_i_container_registry_push_tag_deploy_token_weekly.yml
new file mode 100644
index 0000000000000000000000000000000000000000..7a054110ac956df33a778f1b9cc41655384129b6
--- /dev/null
+++ b/config/metrics/counts_7d/20231227165432_i_container_registry_push_tag_deploy_token_weekly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.user_container_registry.i_container_registry_push_tag_deploy_token_weekly
+description: A weekly count of deploy tokens that have pushed a tag to the registry
+product_section: ops
+product_stage: package
+product_group: container_registry
+value_type: number
+status: active
+milestone: "16.9"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131966
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+  events:
+  - i_container_registry_push_tag_deploy_token
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_7d/20231227165706_i_container_registry_delete_tag_deploy_token_weekly.yml b/config/metrics/counts_7d/20231227165706_i_container_registry_delete_tag_deploy_token_weekly.yml
new file mode 100644
index 0000000000000000000000000000000000000000..afa178c819663952d846fa2a574ca2c3f85b7895
--- /dev/null
+++ b/config/metrics/counts_7d/20231227165706_i_container_registry_delete_tag_deploy_token_weekly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.user_container_registry.i_container_registry_delete_tag_deploy_token_weekly
+description: A weekly count of deploy tokens that have deleted a tag from the registry
+product_section: ops
+product_stage: package
+product_group: container_registry
+value_type: number
+status: active
+milestone: "16.9"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131966
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+  events:
+  - i_container_registry_delete_tag_deploy_token
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_7d/20231227170213_i_container_registry_delete_repository_deploy_token_weekly.yml b/config/metrics/counts_7d/20231227170213_i_container_registry_delete_repository_deploy_token_weekly.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b7498bee37023c5206c572b92b737efb419e5d8c
--- /dev/null
+++ b/config/metrics/counts_7d/20231227170213_i_container_registry_delete_repository_deploy_token_weekly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.user_container_registry.i_container_registry_delete_repository_deploy_token_weekly
+description: A weekly count of deploy tokens that have deleted a repository from the registry
+product_section: ops
+product_stage: package
+product_group: container_registry
+value_type: number
+status: active
+milestone: "16.9"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131966
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+  events:
+  - i_container_registry_delete_repository_deploy_token
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_7d/20231227170547_i_container_registry_create_repository_deploy_token_weekly.yml b/config/metrics/counts_7d/20231227170547_i_container_registry_create_repository_deploy_token_weekly.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3e34df048ccdea7b839a95cd73b05abef8a6ec2b
--- /dev/null
+++ b/config/metrics/counts_7d/20231227170547_i_container_registry_create_repository_deploy_token_weekly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.user_container_registry.i_container_registry_create_repository_deploy_token_weekly
+description: A weekly count of deploy tokens that have created a repository from the registry
+product_section: ops
+product_stage: package
+product_group: container_registry
+value_type: number
+status: active
+milestone: "16.9"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131966
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+  events:
+  - i_container_registry_create_repository_deploy_token
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/lib/json_web_token/rsa_token.rb b/lib/json_web_token/rsa_token.rb
index bcce811cd285bd00805f13ff3ab73e30df7853d8..663c2db0737e3239311f6f1f00ec8b5110e0a937 100644
--- a/lib/json_web_token/rsa_token.rb
+++ b/lib/json_web_token/rsa_token.rb
@@ -2,6 +2,8 @@
 
 module JSONWebToken
   class RSAToken < Token
+    ALGORITHM = 'RS256'
+
     attr_reader :key_file
 
     def initialize(key_file)
@@ -14,7 +16,11 @@ def encoded
         kid: kid,
         typ: 'JWT'
       }
-      JWT.encode(payload, key, 'RS256', headers)
+      JWT.encode(payload, key, ALGORITHM, headers)
+    end
+
+    def self.decode(token, key)
+      JWT.decode(token, key, true, { algorithm: ALGORITHM })
     end
 
     private
diff --git a/spec/lib/json_web_token/rsa_token_spec.rb b/spec/lib/json_web_token/rsa_token_spec.rb
index b77345d8b7a05cc80be2c1a9c6fcc5a6c4a2ea2f..fd553eb181eade633fb323597a9b3ef74d7b327e 100644
--- a/spec/lib/json_web_token/rsa_token_spec.rb
+++ b/spec/lib/json_web_token/rsa_token_spec.rb
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 RSpec.describe JSONWebToken::RSAToken do
-  let(:rsa_key) do
+  let_it_be(:rsa_key) do
     OpenSSL::PKey::RSA.new <<-eos.strip_heredoc
       -----BEGIN RSA PRIVATE KEY-----
       MIIBOgIBAAJBAMA5sXIBE0HwgIB40iNidN4PGWzOyLQK0bsdOBNgpEXkDlZBvnak
@@ -49,4 +49,52 @@
       it { expect { subject }.to raise_error(JWT::DecodeError) }
     end
   end
+
+  describe '.decode' do
+    let(:decoded_token) { described_class.decode(rsa_encoded, rsa_key) }
+
+    context 'with an invalid token' do
+      context 'that is junk' do
+        let(:rsa_encoded) { 'junk' }
+
+        it "raises exception saying 'Not enough or too many segments'" do
+          expect { decoded_token }.to raise_error(JWT::DecodeError, 'Not enough or too many segments')
+        end
+      end
+
+      context 'that has been fiddled with' do
+        let(:rsa_encoded) { rsa_token.encoded.tap { |token| token[0] = 'E' } }
+
+        it "raises exception saying 'Invalid segment encoding'" do
+          expect { decoded_token }.to raise_error(JWT::DecodeError, 'Invalid segment encoding')
+        end
+      end
+
+      context 'that was generated using a different key' do
+        let_it_be(:rsa_key_2) { OpenSSL::PKey::RSA.new 2048 }
+
+        before do
+          # rsa_key is returned for encoding, and rsa_key_2 for decoding
+          allow_any_instance_of(described_class).to receive(:key).and_return(rsa_key, rsa_key_2)
+        end
+
+        it "raises exception saying 'Signature verification failed" do
+          expect { decoded_token }.to raise_error(JWT::VerificationError, 'Signature verification failed')
+        end
+      end
+
+      context 'that is expired' do
+        # Needs the ! so freeze_time() is effective
+        let!(:rsa_encoded) { rsa_token.encoded }
+
+        it "raises exception saying 'Signature has expired'" do
+          # Needs to be 120 seconds, because the default expiry is 60 seconds
+          # with an additional 60 second leeway.
+          travel_to(Time.current + 120) do
+            expect { decoded_token }.to raise_error(JWT::ExpiredSignature, 'Signature has expired')
+          end
+        end
+      end
+    end
+  end
 end
diff --git a/spec/models/container_registry/event_spec.rb b/spec/models/container_registry/event_spec.rb
index d5c3a5fc066f87e46d8110a675ceffa3850b1e60..25d0a993e923d0ae1a3bc0f00cc451a3e01ffd2b 100644
--- a/spec/models/container_registry/event_spec.rb
+++ b/spec/models/container_registry/event_spec.rb
@@ -2,7 +2,7 @@
 
 require 'spec_helper'
 
-RSpec.describe ContainerRegistry::Event do
+RSpec.describe ContainerRegistry::Event, feature_category: :container_registry do
   using RSpec::Parameterized::TableSyntax
 
   let_it_be(:group) { create(:group, name: 'group') }
@@ -112,19 +112,22 @@
   describe '#track!' do
     let_it_be(:container_repository) { create(:container_repository, name: 'container', project: project) }
 
+    let_it_be(:rsa_key) { OpenSSL::PKey::RSA.generate(3072) }
     let(:raw_event) { { 'action' => action, 'target' => target } }
+    let(:key_file) { Tempfile.new('keypath') }
 
-    subject { described_class.new(raw_event).track! }
-
-    shared_examples 'tracking event is sent to HLLRedisCounter with event and originator ID' do |originator_type|
-      it 'fetches the event originator based on username' do
-        count.times do
-          expect(User).to receive(:find_by_username).with(originator.username)
-        end
+    before do
+      allow(Gitlab.config.registry).to receive_messages(enabled: true, issuer: 'rspec', key: key_file.path)
+      allow(OpenSSL::PKey::RSA).to receive(:new).and_return(rsa_key)
 
-        subject
+      allow_next_instance_of(JSONWebToken::RSAToken) do |instance|
+        allow(instance).to receive(:key).and_return(rsa_key)
       end
+    end
+
+    subject { described_class.new(raw_event).track! }
 
+    shared_examples 'tracking event is sent to HLLRedisCounter with event and originator ID' do |originator_type|
       it 'sends a tracking event to HLLRedisCounter' do
         expect(::Gitlab::UsageDataCounters::HLLRedisCounter)
         .to receive(:track_event).with("i_container_registry_#{event}_#{originator_type}", values: originator.id)
@@ -134,6 +137,16 @@
       end
     end
 
+    shared_examples 'event originator is fetched based on ID' do |originator_class|
+      it 'fetches the event originator based on id' do
+        count.times do
+          expect(originator_class).to receive(:find).with(originator.id)
+        end
+
+        subject
+      end
+    end
+
     context 'with a respository target' do
       let(:target) do
         {
@@ -185,43 +198,165 @@
 
     context 'with a deploy token as the actor' do
       let!(:originator) { create(:deploy_token, username: 'username', id: 3) }
-      let(:raw_event) do
-        {
-          'action' => 'push',
-          'target' => { 'tag' => 'latest' },
-          'actor' => { 'user_type' => 'deploy_token', 'name' => originator.username }
-        }
+
+      shared_examples 'no tracking of a deploy token is sent to HLLRedisCounter' do
+        it 'does not send a tracking event to HLLRedisCounter' do
+          expect(DeployToken).not_to receive(:find)
+          expect(DeployToken).not_to receive(:find_by_username)
+          expect(::Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
+
+          expect { subject }.not_to raise_error
+        end
       end
 
-      it 'does not send a tracking event to HLLRedisCounter' do
-        expect(::Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
+      context 'when only username is provided and no deploy_token_id is given' do
+        let(:raw_event) do
+          {
+            'action' => 'push',
+            'target' => { 'tag' => 'latest' },
+            'actor' => { 'user_type' => 'deploy_token', 'name' => originator.username }
+          }
+        end
 
-        subject
+        it_behaves_like 'no tracking of a deploy token is sent to HLLRedisCounter'
+      end
+
+      context 'when no username or deploy_token_id is given' do
+        let(:raw_event) { { 'action' => 'push', 'target' => {}, 'actor' => { 'user_type' => 'deploy_token' } } }
+
+        it_behaves_like 'no tracking of a deploy token is sent to HLLRedisCounter'
+      end
+
+      context 'when deploy_token_id is given' do
+        let(:deploy_token_info) do
+          {
+            token_type: 'deploy_token',
+            username: originator.username,
+            deploy_token_id: originator.id
+          }
+        end
+
+        let(:token) do
+          JSONWebToken::RSAToken.new(rsa_key).tap do |token|
+            token[:user_info] = deploy_token_info
+          end
+        end
+
+        let(:raw_event) do
+          {
+            'action' => action,
+            'target' => target,
+            'actor' => { 'user_type' => 'deploy_token', 'name' => originator.username, 'user' => token.encoded }
+          }
+        end
+
+        where(:target, :action, :event, :count) do
+          { 'tag' => 'latest' }          | 'push'     | 'push_tag'           |  1
+          { 'tag' => 'latest' }          | 'delete'   | 'delete_tag'         |  1
+          { 'repository' => 'foo/bar' }  | 'push'     | 'create_repository'  |  1
+          { 'repository' => 'foo/bar' }  | 'delete'   | 'delete_repository'  |  1
+          { 'tag' => 'latest' }          | 'copy'     | ''                   |  0
+        end
+
+        with_them do
+          it_behaves_like 'event originator is fetched based on ID', DeployToken
+          it_behaves_like 'tracking event is sent to HLLRedisCounter with event and originator ID', :deploy_token
+        end
+
+        context "when there are errors" do
+          let(:action) { 'push' }
+          let(:target) { { 'tag' => 'latest' } }
+
+          context 'when the registry key file does not exist' do
+            before do
+              allow(File).to receive(:read).and_call_original
+              allow(File).to receive(:read).with(key_file.path).and_raise(Errno::ENOENT)
+            end
+
+            it_behaves_like 'no tracking of a deploy token is sent to HLLRedisCounter'
+          end
+
+          [JWT::VerificationError, JWT::DecodeError, JWT::ExpiredSignature, JWT::ImmatureSignature].each do |error|
+            context "when JWT decoding encounters #{error}" do
+              before do
+                allow(JWT).to receive(:decode)
+                .with(token.encoded, rsa_key, true, { algorithm: "RS256" })
+                .and_raise(error)
+              end
+
+              it_behaves_like 'no tracking of a deploy token is sent to HLLRedisCounter'
+            end
+          end
+        end
       end
     end
 
     context 'with a user as the actor' do
       let_it_be(:originator) { create(:user, username: 'username') }
-      let(:raw_event) do
-        {
-          'action' => action,
-          'target' => target,
-          'actor' => { 'user_type' => user_type, 'name' => originator.username }
-        }
+
+      context 'when user_id is available' do
+        let(:user_info) do
+          {
+            token_type: user_type,
+            username: originator.username,
+            user_id: originator.id
+          }
+        end
+
+        let(:token) do
+          JSONWebToken::RSAToken.new(rsa_key).tap do |token|
+            token[:user_info] = user_info
+          end
+        end
+
+        let(:raw_event) do
+          {
+            'action' => action,
+            'target' => target,
+            'actor' => { 'user_type' => user_type, 'name' => originator.username, 'user' => token.encoded }
+          }
+        end
+
+        where(:target, :action, :event, :user_type, :count) do
+          { 'tag' => 'latest' }          | 'push'     | 'push_tag'           |  'personal_access_token'   |  1
+          { 'tag' => 'latest' }          | 'delete'   | 'delete_tag'         |  'personal_access_token'   |  1
+          { 'repository' => 'foo/bar' }  | 'push'     | 'create_repository'  |  'build'                   |  1
+          { 'repository' => 'foo/bar' }  | 'delete'   | 'delete_repository'  |  'gitlab_or_ldap'          |  1
+          { 'repository' => 'foo/bar' }  | 'delete'   | 'delete_repository'  |  'not_a_user'              |  0
+          { 'tag' => 'latest' }          | 'copy'     | ''                   |  nil                       |  0
+          { 'repository' => 'foo/bar' }  | 'copy'     | ''                   |  ''                        |  0
+        end
+
+        with_them do
+          it_behaves_like 'event originator is fetched based on ID', User
+          it_behaves_like 'tracking event is sent to HLLRedisCounter with event and originator ID', :user
+        end
       end
 
-      where(:target, :action, :event, :user_type, :count) do
-        { 'tag' => 'latest' }          | 'push'     | 'push_tag'           |  'personal_access_token'   |  1
-        { 'tag' => 'latest' }          | 'delete'   | 'delete_tag'         |  'personal_access_token'   |  1
-        { 'repository' => 'foo/bar' }  | 'push'     | 'create_repository'  |  'build'                   |  1
-        { 'repository' => 'foo/bar' }  | 'delete'   | 'delete_repository'  |  'gitlab_or_ldap'          |  1
-        { 'repository' => 'foo/bar' }  | 'delete'   | 'delete_repository'  |  'not_a_user'              |  0
-        { 'tag' => 'latest' }          | 'copy'     | ''                   |  nil                       |  0
-        { 'repository' => 'foo/bar' }  | 'copy'     | ''                   |  ''                        |  0
+      context 'when only username is available and user_id is not' do
+        let(:raw_event) do
+          {
+            'action' => 'push',
+            'target' => { 'tag' => 'latest' },
+            'actor' => { 'user_type' => 'personal_access_token', 'name' => originator.username }
+          }
+        end
+
+        it 'does not send a tracking event to HLLRedisCounter' do
+          expect(::Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
+
+          subject
+        end
       end
 
-      with_them do
-        it_behaves_like 'tracking event is sent to HLLRedisCounter with event and originator ID', :user
+      context 'when no username or id is given' do
+        let(:raw_event) { { 'action' => 'push', 'target' => {}, 'actor' => { 'user_type' => 'build' } } }
+
+        it 'does not send a tracking event to HLLRedisCounter' do
+          expect(::Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
+
+          subject
+        end
       end
     end
 
@@ -246,16 +381,5 @@
         subject
       end
     end
-
-    context 'without an actor name' do
-      let(:raw_event) { { 'action' => 'push', 'target' => {}, 'actor' => { 'user_type' => 'personal_access_token' } } }
-
-      it 'does not send a tracking event to HLLRedisCounter' do
-        expect(User).not_to receive(:find_by_username)
-        expect(::Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
-
-        subject
-      end
-    end
   end
 end