diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md
index a37bd906c287fd8efad0a745d86d0f7ea2c32fe3..d9ed849b8e73deef2424c57fb429e7b52edb28c7 100644
--- a/docs/usage/configuration-options.md
+++ b/docs/usage/configuration-options.md
@@ -1348,6 +1348,31 @@ Example:
 
 If enabled, this allows a single TCP connection to remain open for multiple HTTP(S) requests/responses.
 
+### artifactAuth
+
+You may use this field whenever it is needed to only enable authentication for a specific set of managers.
+
+For example, using this option could be used whenever authentication using Git for private composer packages is already being handled through the use of SSH keys, which results in no need for also setting up authentication using tokens.
+
+```json
+{
+  "hostRules": [
+    {
+      "hostType": "gitlab",
+      "matchHost": "gitlab.myorg.com",
+      "token": "abc123",
+      "artifactAuth": ["composer"]
+    }
+  ]
+}
+```
+
+Supported artifactAuth and hostType combinations:
+
+| artifactAuth | hostTypes                                   |
+| ------------ | ------------------------------------------- |
+| `composer`   | `gitlab`, `packagist`, `github`, `git-tags` |
+
 ### matchHost
 
 This can be a base URL (e.g. `https://api.github.com`) or a hostname like `github.com` or `api.github.com`.
diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts
index 233ba616f235a997b67c82550c80d71f33953b4a..4702833112fe325fe75a1e944e38b4c3451a5d25 100644
--- a/lib/config/options/index.ts
+++ b/lib/config/options/index.ts
@@ -2302,6 +2302,20 @@ const options: RenovateOptions[] = [
     env: false,
     experimental: true,
   },
+  {
+    name: 'artifactAuth',
+    description:
+      'A list of package managers to enable artifact auth. Only managers on the list are enabled. All are enabled if `null`',
+    experimental: true,
+    type: 'array',
+    subType: 'string',
+    stage: 'repository',
+    parent: 'hostRules',
+    allowedValues: ['composer'],
+    default: null,
+    cli: false,
+    env: false,
+  },
   {
     name: 'cacheHardTtlMinutes',
     description:
diff --git a/lib/modules/manager/composer/artifacts.spec.ts b/lib/modules/manager/composer/artifacts.spec.ts
index d748617197039686326e41d37d59f4e00628e03d..bd197b7233d21c7a1ec5f06209148ba14cd81473 100644
--- a/lib/modules/manager/composer/artifacts.spec.ts
+++ b/lib/modules/manager/composer/artifacts.spec.ts
@@ -292,6 +292,329 @@ describe('modules/manager/composer/artifacts', () => {
     ]);
   });
 
+  it('does set github COMPOSER_AUTH for github when only hostType git-tags artifactAuth does not include composer', async () => {
+    hostRules.add({
+      hostType: 'github',
+      matchHost: 'api.github.com',
+      token: 'ghs_token',
+    });
+    hostRules.add({
+      hostType: GitTagsDatasource.id,
+      matchHost: 'github.com',
+      token: 'ghp_token',
+      artifactAuth: [],
+    });
+    fs.readLocalFile.mockResolvedValueOnce('{}');
+    const execSnapshots = mockExecAll();
+    fs.readLocalFile.mockResolvedValueOnce('{}');
+    const authConfig = {
+      ...config,
+      registryUrls: ['https://packagist.renovatebot.com'],
+    };
+    git.getRepoStatus.mockResolvedValueOnce(repoStatus);
+    expect(
+      await composer.updateArtifacts({
+        packageFileName: 'composer.json',
+        updatedDeps: [],
+        newPackageFileContent: '{}',
+        config: authConfig,
+      })
+    ).toBeNull();
+    expect(execSnapshots).toMatchObject([
+      {
+        options: {
+          env: {
+            COMPOSER_AUTH: '{"github-oauth":{"github.com":"ghs_token"}}',
+          },
+        },
+      },
+    ]);
+  });
+
+  it('does set github COMPOSER_AUTH for git-tags when only hostType github artifactAuth does not include composer', async () => {
+    hostRules.add({
+      hostType: 'github',
+      matchHost: 'api.github.com',
+      token: 'ghs_token',
+      artifactAuth: [],
+    });
+    hostRules.add({
+      hostType: GitTagsDatasource.id,
+      matchHost: 'github.com',
+      token: 'ghp_token',
+    });
+    fs.readLocalFile.mockResolvedValueOnce('{}');
+    const execSnapshots = mockExecAll();
+    fs.readLocalFile.mockResolvedValueOnce('{}');
+    const authConfig = {
+      ...config,
+      registryUrls: ['https://packagist.renovatebot.com'],
+    };
+    git.getRepoStatus.mockResolvedValueOnce(repoStatus);
+    expect(
+      await composer.updateArtifacts({
+        packageFileName: 'composer.json',
+        updatedDeps: [],
+        newPackageFileContent: '{}',
+        config: authConfig,
+      })
+    ).toBeNull();
+    expect(execSnapshots).toMatchObject([
+      {
+        options: {
+          env: {
+            COMPOSER_AUTH: '{"github-oauth":{"github.com":"ghp_token"}}',
+          },
+        },
+      },
+    ]);
+  });
+
+  it('does not set github COMPOSER_AUTH when artifactAuth does not include composer, for both hostType github & git-tags', async () => {
+    hostRules.add({
+      hostType: 'github',
+      matchHost: 'api.github.com',
+      token: 'ghs_token',
+      artifactAuth: [],
+    });
+    hostRules.add({
+      hostType: GitTagsDatasource.id,
+      matchHost: 'github.com',
+      token: 'ghp_token',
+      artifactAuth: [],
+    });
+    fs.readLocalFile.mockResolvedValueOnce('{}');
+    const execSnapshots = mockExecAll();
+    fs.readLocalFile.mockResolvedValueOnce('{}');
+    const authConfig = {
+      ...config,
+      registryUrls: ['https://packagist.renovatebot.com'],
+    };
+    git.getRepoStatus.mockResolvedValueOnce(repoStatus);
+    expect(
+      await composer.updateArtifacts({
+        packageFileName: 'composer.json',
+        updatedDeps: [],
+        newPackageFileContent: '{}',
+        config: authConfig,
+      })
+    ).toBeNull();
+    expect(execSnapshots[0].options?.env).not.toContainKey('COMPOSER_AUTH');
+  });
+
+  it('does not set gitlab COMPOSER_AUTH when artifactAuth does not include composer', async () => {
+    hostRules.add({
+      hostType: GitTagsDatasource.id,
+      matchHost: 'github.com',
+      token: 'ghp_token',
+    });
+    hostRules.add({
+      hostType: 'gitlab',
+      matchHost: 'gitlab.com',
+      token: 'gitlab-token',
+      artifactAuth: [],
+    });
+    fs.readLocalFile.mockResolvedValueOnce('{}');
+    const execSnapshots = mockExecAll();
+    fs.readLocalFile.mockResolvedValueOnce('{}');
+    const authConfig = {
+      ...config,
+      postUpdateOptions: ['composerGitlabToken'],
+      registryUrls: ['https://packagist.renovatebot.com'],
+    };
+    git.getRepoStatus.mockResolvedValueOnce(repoStatus);
+    expect(
+      await composer.updateArtifacts({
+        packageFileName: 'composer.json',
+        updatedDeps: [],
+        newPackageFileContent: '{}',
+        config: authConfig,
+      })
+    ).toBeNull();
+
+    expect(execSnapshots).toMatchObject([
+      {
+        options: {
+          env: {
+            COMPOSER_AUTH: '{"github-oauth":{"github.com":"ghp_token"}}',
+          },
+        },
+      },
+    ]);
+  });
+
+  it('does not set packagist COMPOSER_AUTH when artifactAuth does not include composer', async () => {
+    hostRules.add({
+      hostType: GitTagsDatasource.id,
+      matchHost: 'github.com',
+      token: 'ghp_token',
+    });
+    hostRules.add({
+      hostType: PackagistDatasource.id,
+      matchHost: 'packagist.renovatebot.com',
+      username: 'some-username',
+      password: 'some-password',
+      artifactAuth: [],
+    });
+    hostRules.add({
+      hostType: PackagistDatasource.id,
+      matchHost: 'https://artifactory.yyyyyyy.com/artifactory/api/composer/',
+      username: 'some-other-username',
+      password: 'some-other-password',
+      artifactAuth: [],
+    });
+    hostRules.add({
+      hostType: PackagistDatasource.id,
+      username: 'some-other-username',
+      password: 'some-other-password',
+      artifactAuth: [],
+    });
+    hostRules.add({
+      hostType: PackagistDatasource.id,
+      matchHost: 'https://packages-bearer.example.com/',
+      token: 'abcdef0123456789',
+      artifactAuth: [],
+    });
+    fs.readLocalFile.mockResolvedValueOnce('{}');
+    const execSnapshots = mockExecAll();
+    fs.readLocalFile.mockResolvedValueOnce('{}');
+    const authConfig = {
+      ...config,
+      postUpdateOptions: ['composerGitlabToken'],
+      registryUrls: ['https://packagist.renovatebot.com'],
+    };
+    git.getRepoStatus.mockResolvedValueOnce(repoStatus);
+    expect(
+      await composer.updateArtifacts({
+        packageFileName: 'composer.json',
+        updatedDeps: [],
+        newPackageFileContent: '{}',
+        config: authConfig,
+      })
+    ).toBeNull();
+
+    expect(execSnapshots).toMatchObject([
+      {
+        options: {
+          env: {
+            COMPOSER_AUTH: '{"github-oauth":{"github.com":"ghp_token"}}',
+          },
+        },
+      },
+    ]);
+  });
+
+  it('does set gitlab COMPOSER_AUTH when artifactAuth does include composer', async () => {
+    hostRules.add({
+      hostType: GitTagsDatasource.id,
+      matchHost: 'github.com',
+      token: 'ghp_token',
+    });
+    hostRules.add({
+      hostType: 'gitlab',
+      matchHost: 'gitlab.com',
+      token: 'gitlab-token',
+      artifactAuth: ['composer'],
+    });
+    fs.readLocalFile.mockResolvedValueOnce('{}');
+    const execSnapshots = mockExecAll();
+    fs.readLocalFile.mockResolvedValueOnce('{}');
+    const authConfig = {
+      ...config,
+      postUpdateOptions: ['composerGitlabToken'],
+      registryUrls: ['https://packagist.renovatebot.com'],
+    };
+    git.getRepoStatus.mockResolvedValueOnce(repoStatus);
+    expect(
+      await composer.updateArtifacts({
+        packageFileName: 'composer.json',
+        updatedDeps: [],
+        newPackageFileContent: '{}',
+        config: authConfig,
+      })
+    ).toBeNull();
+
+    expect(execSnapshots).toMatchObject([
+      {
+        options: {
+          env: {
+            COMPOSER_AUTH:
+              '{"github-oauth":{"github.com":"ghp_token"},' +
+              '"gitlab-token":{"gitlab.com":"gitlab-token"},' +
+              '"gitlab-domains":["gitlab.com"]}',
+          },
+        },
+      },
+    ]);
+  });
+
+  it('does set packagist COMPOSER_AUTH when artifactAuth does include composer', async () => {
+    hostRules.add({
+      hostType: GitTagsDatasource.id,
+      matchHost: 'github.com',
+      token: 'ghp_token',
+    });
+    hostRules.add({
+      hostType: PackagistDatasource.id,
+      matchHost: 'packagist.renovatebot.com',
+      username: 'some-username',
+      password: 'some-password',
+      artifactAuth: ['composer'],
+    });
+    hostRules.add({
+      hostType: PackagistDatasource.id,
+      matchHost: 'https://artifactory.yyyyyyy.com/artifactory/api/composer/',
+      username: 'some-other-username',
+      password: 'some-other-password',
+      artifactAuth: ['composer'],
+    });
+    hostRules.add({
+      hostType: PackagistDatasource.id,
+      username: 'some-other-username',
+      password: 'some-other-password',
+      artifactAuth: ['composer'],
+    });
+    hostRules.add({
+      hostType: PackagistDatasource.id,
+      matchHost: 'https://packages-bearer.example.com/',
+      token: 'abcdef0123456789',
+      artifactAuth: ['composer'],
+    });
+    fs.readLocalFile.mockResolvedValueOnce('{}');
+    const execSnapshots = mockExecAll();
+    fs.readLocalFile.mockResolvedValueOnce('{}');
+    const authConfig = {
+      ...config,
+      postUpdateOptions: ['composerGitlabToken'],
+      registryUrls: ['https://packagist.renovatebot.com'],
+    };
+    git.getRepoStatus.mockResolvedValueOnce(repoStatus);
+    expect(
+      await composer.updateArtifacts({
+        packageFileName: 'composer.json',
+        updatedDeps: [],
+        newPackageFileContent: '{}',
+        config: authConfig,
+      })
+    ).toBeNull();
+
+    expect(execSnapshots).toMatchObject([
+      {
+        options: {
+          env: {
+            COMPOSER_AUTH:
+              '{"github-oauth":{"github.com":"ghp_token"},' +
+              '"http-basic":{' +
+              '"packagist.renovatebot.com":{"username":"some-username","password":"some-password"},' +
+              '"artifactory.yyyyyyy.com":{"username":"some-other-username","password":"some-other-password"}' +
+              '},' +
+              '"bearer":{"packages-bearer.example.com":"abcdef0123456789"}}',
+          },
+        },
+      },
+    ]);
+  });
+
   it('returns updated composer.lock', async () => {
     fs.readLocalFile.mockResolvedValueOnce('{}');
     const execSnapshots = mockExecAll();
diff --git a/lib/modules/manager/composer/artifacts.ts b/lib/modules/manager/composer/artifacts.ts
index 0eae7fefdefad1bbb38ad6d91d8fefad8c73adf0..cc6acbbf266ff03cd33f3f20c25bca3e15b1a203 100644
--- a/lib/modules/manager/composer/artifacts.ts
+++ b/lib/modules/manager/composer/artifacts.ts
@@ -27,6 +27,7 @@ import {
   findGithubToken,
   getComposerArguments,
   getPhpConstraint,
+  isArtifactAuthEnabled,
   requireComposerDependencyInstallation,
   takePersonalAccessTokenIfPossible,
 } from './utils';
@@ -34,27 +35,36 @@ import {
 function getAuthJson(): string | null {
   const authJson: AuthJson = {};
 
-  const githubToken = findGithubToken({
+  const githubHostRule = hostRules.find({
     hostType: 'github',
     url: 'https://api.github.com/',
   });
 
-  const gitTagsGithubToken = findGithubToken({
+  const gitTagsHostRule = hostRules.find({
     hostType: GitTagsDatasource.id,
     url: 'https://github.com',
   });
 
   const selectedGithubToken = takePersonalAccessTokenIfPossible(
-    githubToken,
-    gitTagsGithubToken
+    isArtifactAuthEnabled(githubHostRule)
+      ? findGithubToken(githubHostRule)
+      : undefined,
+    isArtifactAuthEnabled(gitTagsHostRule)
+      ? findGithubToken(gitTagsHostRule)
+      : undefined
   );
+
   if (selectedGithubToken) {
     authJson['github-oauth'] = {
       'github.com': selectedGithubToken,
     };
   }
 
-  hostRules.findAll({ hostType: 'gitlab' })?.forEach((gitlabHostRule) => {
+  for (const gitlabHostRule of hostRules.findAll({ hostType: 'gitlab' })) {
+    if (!isArtifactAuthEnabled(gitlabHostRule)) {
+      continue;
+    }
+
     if (gitlabHostRule?.token) {
       const host = gitlabHostRule.resolvedHost ?? 'gitlab.com';
       authJson['gitlab-token'] = authJson['gitlab-token'] ?? {};
@@ -65,20 +75,24 @@ function getAuthJson(): string | null {
         ...(authJson['gitlab-domains'] ?? []),
       ];
     }
-  });
+  }
 
-  hostRules
-    .findAll({ hostType: PackagistDatasource.id })
-    ?.forEach((hostRule) => {
-      const { resolvedHost, username, password, token } = hostRule;
-      if (resolvedHost && username && password) {
-        authJson['http-basic'] = authJson['http-basic'] ?? {};
-        authJson['http-basic'][resolvedHost] = { username, password };
-      } else if (resolvedHost && token) {
-        authJson.bearer = authJson.bearer ?? {};
-        authJson.bearer[resolvedHost] = token;
-      }
-    });
+  for (const packagistHostRule of hostRules.findAll({
+    hostType: PackagistDatasource.id,
+  })) {
+    if (!isArtifactAuthEnabled(packagistHostRule)) {
+      continue;
+    }
+
+    const { resolvedHost, username, password, token } = packagistHostRule;
+    if (resolvedHost && username && password) {
+      authJson['http-basic'] = authJson['http-basic'] ?? {};
+      authJson['http-basic'][resolvedHost] = { username, password };
+    } else if (resolvedHost && token) {
+      authJson.bearer = authJson.bearer ?? {};
+      authJson.bearer[resolvedHost] = token;
+    }
+  }
 
   return is.emptyObject(authJson) ? null : JSON.stringify(authJson);
 }
diff --git a/lib/modules/manager/composer/utils.spec.ts b/lib/modules/manager/composer/utils.spec.ts
index c591825be756637fe63d70462f46099c57efcb06..481df517e6f2602755d48033439d9c9297d9c975 100644
--- a/lib/modules/manager/composer/utils.spec.ts
+++ b/lib/modules/manager/composer/utils.spec.ts
@@ -308,21 +308,26 @@ describe('modules/manager/composer/utils', () => {
         matchHost: 'github.com',
         token: TOKEN_STRING,
       });
-      expect(
-        findGithubToken({
-          hostType: GitTagsDatasource.id,
-          url: 'https://github.com',
-        })
-      ).toEqual(TOKEN_STRING);
+
+      const foundHostRule = hostRules.find({
+        hostType: GitTagsDatasource.id,
+        url: 'https://github.com',
+      });
+
+      expect(findGithubToken(foundHostRule)).toEqual(TOKEN_STRING);
     });
 
-    it('returns undefined when no hostRule match search', () => {
-      expect(
-        findGithubToken({
-          hostType: GitTagsDatasource.id,
-          url: 'https://github.com',
-        })
-      ).toBeUndefined();
+    it('returns undefined when no token is defined', () => {
+      hostRules.add({
+        hostType: GitTagsDatasource.id,
+        matchHost: 'github.com',
+      });
+
+      const foundHostRule = hostRules.find({
+        hostType: GitTagsDatasource.id,
+        url: 'https://github.com',
+      });
+      expect(findGithubToken(foundHostRule)).toBeUndefined();
     });
 
     it('remove x-access-token token prefix', () => {
@@ -333,12 +338,12 @@ describe('modules/manager/composer/utils', () => {
         matchHost: 'github.com',
         token: TOKEN_STRING_WITH_PREFIX,
       });
-      expect(
-        findGithubToken({
-          hostType: GitTagsDatasource.id,
-          url: 'https://github.com',
-        })
-      ).toEqual(TOKEN_STRING);
+
+      const foundHostRule = hostRules.find({
+        hostType: GitTagsDatasource.id,
+        url: 'https://github.com',
+      });
+      expect(findGithubToken(foundHostRule)).toEqual(TOKEN_STRING);
     });
   });
 
diff --git a/lib/modules/manager/composer/utils.ts b/lib/modules/manager/composer/utils.ts
index 330f50bc713892cfed4d7b23b8f6ee05d72b8f72..8342798971adb7cdec3f20ccbba900da86a09a6a 100644
--- a/lib/modules/manager/composer/utils.ts
+++ b/lib/modules/manager/composer/utils.ts
@@ -3,8 +3,8 @@
 import { quote } from 'shlex';
 import { GlobalConfig } from '../../../config/global';
 import { logger } from '../../../logger';
+import type { HostRuleSearchResult } from '../../../types';
 import type { ToolConstraint } from '../../../util/exec/types';
-import { HostRuleSearch, find as findHostRule } from '../../../util/host-rules';
 import { api, id as composerVersioningId } from '../../versioning/composer';
 import type { UpdateArtifactsConfig } from '../types';
 import type { ComposerConfig, ComposerLock } from './types';
@@ -111,8 +111,10 @@ export function extractConstraints(
   return res;
 }
 
-export function findGithubToken(search: HostRuleSearch): string | undefined {
-  return findHostRule(search)?.token?.replace('x-access-token:', '');
+export function findGithubToken(
+  searchResult: HostRuleSearchResult
+): string | undefined {
+  return searchResult?.token?.replace('x-access-token:', '');
 }
 
 export function isGithubPersonalAccessToken(token: string): boolean {
@@ -173,3 +175,7 @@ export function takePersonalAccessTokenIfPossible(
 
   return githubToken;
 }
+
+export function isArtifactAuthEnabled(rule: HostRuleSearchResult): boolean {
+  return !rule.artifactAuth || rule.artifactAuth.includes('composer');
+}
diff --git a/lib/types/host-rules.ts b/lib/types/host-rules.ts
index d5b23a80ac246bf092b404c793b66f43afa6fabf..ac02a813c38a0bde06588ca1985272ea89df55fd 100644
--- a/lib/types/host-rules.ts
+++ b/lib/types/host-rules.ts
@@ -14,6 +14,7 @@ export interface HostRuleSearchResult {
 
   dnsCache?: boolean;
   keepalive?: boolean;
+  artifactAuth?: string[] | null;
 }
 
 export interface HostRule extends HostRuleSearchResult {