diff --git a/doc/api/admin/token.md b/doc/api/admin/token.md
index 01266a4518bcb71dd01f0d409670b8411fc0d2c2..b305a2abfe141a7e797f5ce3ce8368974b1e3e18 100644
--- a/doc/api/admin/token.md
+++ b/doc/api/admin/token.md
@@ -33,6 +33,7 @@ Prerequisites:
 > - [CI/CD Job Tokens added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/175234) in GitLab 17.9.
 > - [Feature flags client tokens added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/177431) in GitLab 17.9.
 > - [GitLab session cookies added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/178022) in GitLab 17.9.
+> - [Incoming email tokens added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/177077) in GitLab 17.9.
 
 Gets information for a given token. This endpoint supports the following tokens:
 
@@ -47,6 +48,7 @@ Gets information for a given token. This endpoint supports the following tokens:
 - [CI/CD Job Tokens](../../security/tokens/_index.md#cicd-job-tokens)
 - [Feature flags client tokens](../../operations/feature_flags.md#get-access-credentials)
 - [GitLab session cookies](../../user/profile/active_sessions.md)
+- [Incoming email tokens](../../security/tokens/_index.md#incoming-email-token)
 
 ```plaintext
 POST /api/v4/admin/token
diff --git a/lib/authn/agnostic_token_identifier.rb b/lib/authn/agnostic_token_identifier.rb
index e727b9763e16cb7b439a609a4055ed9ed98b3a11..01b83cb60ebbb9c28bac972d80fcace48929917b 100644
--- a/lib/authn/agnostic_token_identifier.rb
+++ b/lib/authn/agnostic_token_identifier.rb
@@ -14,7 +14,8 @@ class AgnosticTokenIdentifier
       ::Authn::Tokens::CiTriggerToken,
       ::Authn::Tokens::CiJobToken,
       ::Authn::Tokens::FeatureFlagsClientToken,
-      ::Authn::Tokens::GitlabSession
+      ::Authn::Tokens::GitlabSession,
+      ::Authn::Tokens::IncomingEmailToken
     ].freeze
 
     def self.token_for(plaintext, source)
diff --git a/lib/authn/tokens/incoming_email_token.rb b/lib/authn/tokens/incoming_email_token.rb
new file mode 100644
index 0000000000000000000000000000000000000000..e4d2fd47686d5bb95e1c1eada7f251dc7d1a2fa4
--- /dev/null
+++ b/lib/authn/tokens/incoming_email_token.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal:true
+
+module Authn
+  module Tokens
+    class IncomingEmailToken
+      def self.prefix?(plaintext)
+        plaintext.start_with?(::User::INCOMING_MAIL_TOKEN_PREFIX)
+      end
+
+      attr_reader :revocable, :source
+
+      def initialize(plaintext, source)
+        @revocable = ::User.find_by_incoming_email_token(plaintext)
+        @source = source
+      end
+
+      def present_with
+        ::API::Entities::User
+      end
+
+      def revoke!(_current_user)
+        raise ::Authn::AgnosticTokenIdentifier::NotFoundError, 'Not Found' if revocable.blank?
+
+        raise ::Authn::AgnosticTokenIdentifier::UnsupportedTokenError, 'Unsupported token type'
+      end
+    end
+  end
+end
diff --git a/spec/lib/authn/agnostic_token_identifier_spec.rb b/spec/lib/authn/agnostic_token_identifier_spec.rb
index 09d3b4a90c8594680a117b119c9500583abcf2b8..923f67fcc87e140a9c50b9d79ed504e65e6fc3d1 100644
--- a/spec/lib/authn/agnostic_token_identifier_spec.rb
+++ b/spec/lib/authn/agnostic_token_identifier_spec.rb
@@ -24,6 +24,7 @@
   let_it_be(:ci_trigger_token) { create(:ci_trigger).token }
   let_it_be(:feature_flags_client_token) { create(:operations_feature_flags_client).token }
   let_it_be(:gitlab_session) { '_gitlab_session=session_id' }
+  let_it_be(:incoming_email_token) { user.incoming_email_token }
 
   subject(:token) { described_class.token_for(plaintext, :group_token_revocation_service) }
 
@@ -39,6 +40,7 @@
       ref(:ci_trigger_token) | ::Authn::Tokens::CiTriggerToken
       ref(:feature_flags_client_token) | ::Authn::Tokens::FeatureFlagsClientToken
       ref(:gitlab_session) | ::Authn::Tokens::GitlabSession
+      ref(:incoming_email_token) | ::Authn::Tokens::IncomingEmailToken
       'unsupported' | NilClass
     end
 
diff --git a/spec/lib/authn/tokens/incoming_email_token_spec.rb b/spec/lib/authn/tokens/incoming_email_token_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..bf44a3f4650eb85b6079bf73e7364b1eac2dc8a5
--- /dev/null
+++ b/spec/lib/authn/tokens/incoming_email_token_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Authn::Tokens::IncomingEmailToken, feature_category: :system_access do
+  let_it_be(:user) { create(:user) }
+
+  subject(:token) { described_class.new(plaintext, :api_admin_token) }
+
+  context 'with valid incoming email token' do
+    let(:plaintext) { user.incoming_email_token }
+    let(:valid_revocable) { user }
+
+    it_behaves_like 'finding the valid revocable'
+
+    describe '#revoke!' do
+      it 'does not support revocation yet' do
+        expect do
+          token.revoke!(user)
+        end.to raise_error(::Authn::AgnosticTokenIdentifier::UnsupportedTokenError, 'Unsupported token type')
+      end
+    end
+  end
+
+  it_behaves_like 'token handling with unsupported token type'
+end
diff --git a/spec/requests/api/admin/token_spec.rb b/spec/requests/api/admin/token_spec.rb
index 40781e461c1f1f20c64fd092476371a22a990245..424783c5fb1e9f8483d956b11f564ad1bbbfc9e2 100644
--- a/spec/requests/api/admin/token_spec.rb
+++ b/spec/requests/api/admin/token_spec.rb
@@ -70,6 +70,7 @@
             [ref(:group_deploy_token), lazy { group_deploy_token.token }],
             [ref(:project_deploy_token), lazy { project_deploy_token.token }],
             [ref(:user), lazy { user.feed_token }],
+            [ref(:user), lazy { user.incoming_email_token }],
             [ref(:oauth_application), lazy { oauth_application.plaintext_secret }],
             [ref(:cluster_agent_token), lazy { cluster_agent_token.token }],
             [ref(:runner_authentication_token), lazy { runner_authentication_token.token }],