diff --git a/doc/api/admin/token.md b/doc/api/admin/token.md
index e9c109158839eef367575e9a26ef227bbaf430b5..74c8c31b2302ae75ab61e31e4762b62e975475f0 100644
--- a/doc/api/admin/token.md
+++ b/doc/api/admin/token.md
@@ -14,6 +14,7 @@ DETAILS:
 
 > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/165157) in GitLab 17.5 [with a flag](../../administration/feature_flags.md) named `admin_agnostic_token_finder`. Disabled by default.
 > - [Feed tokens added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/169821) in GitLab 17.6.
+> - [OAuth application secrets added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/172985) in GitLab 17.7.
 
 FLAG:
 The availability of this feature is controlled by a feature flag.
@@ -37,6 +38,7 @@ Supported tokens:
 - [Personal access tokens](../../user/profile/personal_access_tokens.md)
 - [Deploy tokens](../../user/project/deploy_tokens/index.md)
 - [Feed tokens](../../security/tokens/index.md#feed-token)
+- [OAuth application secrets](../../integration/oauth_provider.md)
 
 ```plaintext
 POST /api/v4/admin/token
diff --git a/lib/api/admin/token.rb b/lib/api/admin/token.rb
index 9a54c95526f1540397a6e9c8d727af34fbaf7376..2100d2104c7a4d653ce1d1a41c598e99e9da68c0 100644
--- a/lib/api/admin/token.rb
+++ b/lib/api/admin/token.rb
@@ -11,7 +11,7 @@ def identify_token(plaintext)
           token = ::Authn::AgnosticTokenIdentifier.token_for(plaintext, AUDIT_SOURCE)
           raise ArgumentError, 'Token type not supported.' if token.blank?
 
-          token.revocable
+          token
         end
       end
 
@@ -45,12 +45,11 @@ def identify_token(plaintext)
         end
         post 'token' do
           identified_token = identify_token(params[:token])
-
-          render_api_error!({ error: 'Not found' }, :not_found) if identified_token.nil?
+          render_api_error!({ error: 'Not found' }, :not_found) if identified_token.revocable.nil?
 
           status :ok
 
-          present identified_token, with: "API::Entities::#{identified_token.class.name}".constantize
+          present identified_token.revocable, with: identified_token.present_with
         end
       end
     end
diff --git a/lib/authn/agnostic_token_identifier.rb b/lib/authn/agnostic_token_identifier.rb
index 672f03d6eba43135f5ee799850f26abb9f53282c..7f04f75e1bcc727c8bced6654c72152506c4d5f4 100644
--- a/lib/authn/agnostic_token_identifier.rb
+++ b/lib/authn/agnostic_token_identifier.rb
@@ -3,10 +3,12 @@
 module Authn
   class AgnosticTokenIdentifier
     NotFoundError = Class.new(StandardError)
+    UnsupportedTokenError = Class.new(StandardError)
     TOKEN_TYPES = [
       ::Authn::Tokens::DeployToken,
       ::Authn::Tokens::FeedToken,
-      ::Authn::Tokens::PersonalAccessToken
+      ::Authn::Tokens::PersonalAccessToken,
+      ::Authn::Tokens::OauthApplicationSecret
     ].freeze
 
     def self.token_for(plaintext, source)
diff --git a/lib/authn/tokens/deploy_token.rb b/lib/authn/tokens/deploy_token.rb
index 43b694adf172f222ccfba11dcb0101fa8973ffd8..7ebaf1d98d482ebfe4f4f9c8bada2783071f025c 100644
--- a/lib/authn/tokens/deploy_token.rb
+++ b/lib/authn/tokens/deploy_token.rb
@@ -14,6 +14,10 @@ def initialize(plaintext, source)
         @source = source
       end
 
+      def present_with
+        ::API::Entities::DeployToken
+      end
+
       def revoke!(current_user)
         raise ::Authn::AgnosticTokenIdentifier::NotFoundError, 'Not Found' if revocable.blank?
 
diff --git a/lib/authn/tokens/feed_token.rb b/lib/authn/tokens/feed_token.rb
index 1b425c764038679098ec36a2f2ae768aa7e3749a..b46c35632c95659c7588ed48d63f930e87087e22 100644
--- a/lib/authn/tokens/feed_token.rb
+++ b/lib/authn/tokens/feed_token.rb
@@ -14,6 +14,10 @@ def initialize(plaintext, source)
         @source = source
       end
 
+      def present_with
+        ::API::Entities::User
+      end
+
       def revoke!(current_user)
         raise ::Authn::AgnosticTokenIdentifier::NotFoundError, 'Not Found' if revocable.blank?
 
diff --git a/lib/authn/tokens/oauth_application_secret.rb b/lib/authn/tokens/oauth_application_secret.rb
new file mode 100644
index 0000000000000000000000000000000000000000..84432afeaf735797fadddb197e6ebb380d54999c
--- /dev/null
+++ b/lib/authn/tokens/oauth_application_secret.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal:true
+
+module Authn
+  module Tokens
+    class OauthApplicationSecret
+      def self.prefix?(plaintext)
+        prefix =
+          ::Gitlab::DoorkeeperSecretStoring::Token::UniqueApplicationToken::OAUTH_APPLICATION_SECRET_PREFIX_FORMAT
+          .split('-').first
+
+        plaintext.start_with?(prefix)
+      end
+
+      attr_reader :revocable, :source
+
+      def initialize(plaintext, source)
+        @revocable = ::Doorkeeper::Application.find_by_plaintext_token(:secret, plaintext)
+        @source = source
+      end
+
+      def present_with
+        ::API::Entities::Application
+      end
+
+      def revoke!(_current_user)
+        raise ::Authn::AgnosticTokenIdentifier::NotFoundError, 'Not Found' if revocable.blank?
+
+        raise ::Authn::AgnosticTokenIdentifier::UnsupportedTokenError, 'Revocation not supported for this token type'
+      end
+    end
+  end
+end
diff --git a/lib/authn/tokens/personal_access_token.rb b/lib/authn/tokens/personal_access_token.rb
index 669debaf2b47aa4ba9a7e798a27d3d47070f543d..67ef8681d7d164faccbedf3b8a9d353050308c6a 100644
--- a/lib/authn/tokens/personal_access_token.rb
+++ b/lib/authn/tokens/personal_access_token.rb
@@ -17,6 +17,10 @@ def initialize(plaintext, source)
         @source = source
       end
 
+      def present_with
+        ::API::Entities::PersonalAccessToken
+      end
+
       def revoke!(current_user)
         raise ::Authn::AgnosticTokenIdentifier::NotFoundError, 'Not Found' if revocable.blank?
 
diff --git a/spec/lib/authn/agnostic_token_identifier_spec.rb b/spec/lib/authn/agnostic_token_identifier_spec.rb
index b3d96cb6a46535aae3bf21e1c0aaec9106a5b218..386b91894c2194a7ca984e26561f098e2ddc25dc 100644
--- a/spec/lib/authn/agnostic_token_identifier_spec.rb
+++ b/spec/lib/authn/agnostic_token_identifier_spec.rb
@@ -9,6 +9,7 @@
   let_it_be(:deploy_token) { create(:deploy_token).token }
   let_it_be(:feed_token) { user.feed_token }
   let_it_be(:personal_access_token) { create(:personal_access_token, user: user).token }
+  let_it_be(:oauth_application_secret) { create(:oauth_application).plaintext_secret }
 
   subject(:token) { described_class.token_for(plaintext, :group_token_revocation_service) }
 
@@ -17,6 +18,7 @@
       ref(:personal_access_token) | ::Authn::Tokens::PersonalAccessToken
       ref(:feed_token) | ::Authn::Tokens::FeedToken
       ref(:deploy_token) | ::Authn::Tokens::DeployToken
+      ref(:oauth_application_secret) | ::Authn::Tokens::OauthApplicationSecret
       'unsupported' | NilClass
     end
 
diff --git a/spec/lib/authn/tokens/oauth_application_secret_spec.rb b/spec/lib/authn/tokens/oauth_application_secret_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b0857f27088786c392b314b6e2cbf54a615a256c
--- /dev/null
+++ b/spec/lib/authn/tokens/oauth_application_secret_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Authn::Tokens::OauthApplicationSecret, feature_category: :system_access do
+  let_it_be(:user) { create(:user) }
+
+  let(:oauth_application_secret) { create(:oauth_application) }
+
+  subject(:token) { described_class.new(plaintext, :api_admin_token) }
+
+  context 'with valid oauth application secret' do
+    let(:plaintext) { oauth_application_secret.plaintext_secret }
+    let(:valid_revocable) { oauth_application_secret }
+
+    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,
+          'Revocation not supported for this 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 5cc09953497d7221fe1cea101026766796049375..2f411f6aab1a34e1a3d7f0bdf551850a4ce59504 100644
--- a/spec/requests/api/admin/token_spec.rb
+++ b/spec/requests/api/admin/token_spec.rb
@@ -10,6 +10,8 @@
 
   let_it_be(:personal_access_token) { create(:personal_access_token, user: user) }
   let_it_be(:deploy_token) { create(:deploy_token) }
+  let_it_be(:oauth_application) { create(:oauth_application) }
+
   let(:plaintext) { nil }
   let(:params) { { token: plaintext } }
 
@@ -22,7 +24,8 @@
           [
             [ref(:personal_access_token), lazy { personal_access_token.token }],
             [ref(:deploy_token), lazy { deploy_token.token }],
-            [ref(:user), lazy { user.feed_token }]
+            [ref(:user), lazy { user.feed_token }],
+            [ref(:oauth_application), lazy { oauth_application.plaintext_secret }]
           ]
         end
 
diff --git a/spec/support/shared_examples/authn/token_shared_examples.rb b/spec/support/shared_examples/authn/token_shared_examples.rb
index a0ff50401de40e27112879e34029126efa5b8cd8..12c9741151f24f99586566dbeb91f5cef90d8480 100644
--- a/spec/support/shared_examples/authn/token_shared_examples.rb
+++ b/spec/support/shared_examples/authn/token_shared_examples.rb
@@ -27,4 +27,10 @@
       expect(token.revocable).to eq(valid_revocable)
     end
   end
+
+  describe '#present_with' do
+    it 'returns a constant that is a subclass of Grape::Entity' do
+      expect(token.present_with).to be <= Grape::Entity
+    end
+  end
 end