diff --git a/docs/usage/getting-started/private-packages.md b/docs/usage/getting-started/private-packages.md
index 451cb54b4ecb64846ed2c31f77b2f8d34ac24f43..c6d4c6a0e64f66e6f3c428faaec5b902cec88ee3 100644
--- a/docs/usage/getting-started/private-packages.md
+++ b/docs/usage/getting-started/private-packages.md
@@ -179,6 +179,21 @@ The following details the most common/popular manager artifacts updating and how
 
 Any `hostRules` token for `github.com` or `gitlab.com` are found and written out to `COMPOSER_AUTH` in env for Composer to parse.
 Any `hostRules` with `hostType=packagist` are also included.
+For dependencies on `github.com` without a packagist server, a hostRule with `hostType=git-tags` should be used with a personal access token (not an application token).
+Do not add a hostRule with `hostType=github` because it can override the default renovate application token for everything else and cause unwanted side effects.
+
+The repository in `composer.json` should have the `vcs` type with a `https` url. Ex:
+
+```json
+{
+  "repositories": [
+    {
+      "type": "vcs",
+      "url": "https://github.com/organization/private-repository"
+    }
+  ]
+}
+```
 
 ### gomod
 
diff --git a/lib/modules/manager/composer/artifacts.spec.ts b/lib/modules/manager/composer/artifacts.spec.ts
index 5626a6508599c04fdbc07cb3fa05627d1b26d770..f28bdec566600f8393811b253607f10c0397f7a1 100644
--- a/lib/modules/manager/composer/artifacts.spec.ts
+++ b/lib/modules/manager/composer/artifacts.spec.ts
@@ -8,6 +8,7 @@ import * as docker from '../../../util/exec/docker';
 import type { StatusResult } from '../../../util/git/types';
 import * as hostRules from '../../../util/host-rules';
 import * as _datasource from '../../datasource';
+import { GitTagsDatasource } from '../../datasource/git-tags';
 import { PackagistDatasource } from '../../datasource/packagist';
 import type { UpdateArtifactsConfig } from '../types';
 import * as composer from '.';
@@ -113,7 +114,13 @@ describe('modules/manager/composer/artifacts', () => {
     hostRules.add({
       hostType: PlatformId.Github,
       matchHost: 'api.github.com',
-      token: 'github-token',
+      token: 'ghp_github-token',
+    });
+    // This rule should not affect the result the Github rule has priority to avoid breaking changes.
+    hostRules.add({
+      hostType: GitTagsDatasource.id,
+      matchHost: 'github.com',
+      token: 'ghp_git-tags-token',
     });
     hostRules.add({
       hostType: PlatformId.Gitlab,
@@ -165,7 +172,14 @@ describe('modules/manager/composer/artifacts', () => {
           cwd: '/tmp/github/some/repo',
           env: {
             COMPOSER_AUTH:
-              '{"github-oauth":{"github.com":"github-token"},"gitlab-token":{"gitlab.com":"gitlab-token"},"gitlab-domains":["gitlab.com"],"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"}}',
+              '{"github-oauth":{"github.com":"ghp_git-tags-token"},' +
+              '"gitlab-token":{"gitlab.com":"gitlab-token"},' +
+              '"gitlab-domains":["gitlab.com"],' +
+              '"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"}}',
             COMPOSER_CACHE_DIR: '/tmp/renovate/cache/others/composer',
           },
         },
@@ -173,6 +187,78 @@ describe('modules/manager/composer/artifacts', () => {
     ]);
   });
 
+  it('git-tags hostRule for github.com set github-token in COMPOSER_AUTH', async () => {
+    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('Skip github application access token hostRules in COMPOSER_AUTH', async () => {
+    hostRules.add({
+      hostType: PlatformId.Github,
+      matchHost: 'api.github.com',
+      token: 'ghs_token',
+    });
+    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('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 9e0d55a8064c5ae5483f1b971ce0f4d432942b4d..a81478f1360bc4bf3665eb6549218cf5f1511306 100644
--- a/lib/modules/manager/composer/artifacts.ts
+++ b/lib/modules/manager/composer/artifacts.ts
@@ -19,12 +19,14 @@ import {
 import { getRepoStatus } from '../../../util/git';
 import * as hostRules from '../../../util/host-rules';
 import { regEx } from '../../../util/regex';
+import { GitTagsDatasource } from '../../datasource/git-tags';
 import { PackagistDatasource } from '../../datasource/packagist';
 import type { UpdateArtifact, UpdateArtifactsResult } from '../types';
 import type { AuthJson, ComposerLock } from './types';
 import {
   composerVersioningId,
   extractConstraints,
+  findGithubPersonalAccessToken,
   getComposerArguments,
   getPhpConstraint,
   requireComposerDependencyInstallation,
@@ -33,13 +35,23 @@ import {
 function getAuthJson(): string | null {
   const authJson: AuthJson = {};
 
-  const githubCredentials = hostRules.find({
+  const githubToken = findGithubPersonalAccessToken({
     hostType: PlatformId.Github,
     url: 'https://api.github.com/',
   });
-  if (githubCredentials?.token) {
+  if (githubToken) {
     authJson['github-oauth'] = {
-      'github.com': githubCredentials.token.replace('x-access-token:', ''),
+      'github.com': githubToken,
+    };
+  }
+
+  const gitTagsGithubToken = findGithubPersonalAccessToken({
+    hostType: GitTagsDatasource.id,
+    url: 'https://github.com',
+  });
+  if (gitTagsGithubToken) {
+    authJson['github-oauth'] = {
+      'github.com': gitTagsGithubToken,
     };
   }
 
diff --git a/lib/modules/manager/composer/utils.spec.ts b/lib/modules/manager/composer/utils.spec.ts
index 4f2e0fd5ff76aa3a10f3a8cce4a356888044b45b..a6d02e0c74ba67d6ab4c38bc3e090d84a8a040c7 100644
--- a/lib/modules/manager/composer/utils.spec.ts
+++ b/lib/modules/manager/composer/utils.spec.ts
@@ -1,13 +1,21 @@
 import { GlobalConfig } from '../../../config/global';
+import * as hostRules from '../../../util/host-rules';
+import { GitTagsDatasource } from '../../datasource/git-tags';
 import {
   extractConstraints,
+  findGithubPersonalAccessToken,
   getComposerArguments,
+  isPersonalAccessToken,
   requireComposerDependencyInstallation,
 } from './utils';
 
 jest.mock('../../datasource');
 
 describe('modules/manager/composer/utils', () => {
+  beforeEach(() => {
+    hostRules.clear();
+  });
+
   describe('extractConstraints', () => {
     it('returns from require', () => {
       expect(
@@ -288,4 +296,59 @@ describe('modules/manager/composer/utils', () => {
       ).toBeFalse();
     });
   });
+
+  describe('findGithubPersonalAccessToken', () => {
+    it('returns the token string when hostRule match search with a valid personal access token', () => {
+      const TOKEN_STRING = 'ghp_TOKEN';
+      hostRules.add({
+        hostType: GitTagsDatasource.id,
+        matchHost: 'github.com',
+        token: TOKEN_STRING,
+      });
+      expect(
+        findGithubPersonalAccessToken({
+          hostType: GitTagsDatasource.id,
+          url: 'https://github.com',
+        })
+      ).toEqual(TOKEN_STRING);
+    });
+
+    it('returns undefined when hostRule match search with a invalid personal access token', () => {
+      const TOKEN_STRING = 'NOT_A_PERSONAL_ACCESS_TOKEN';
+      hostRules.add({
+        hostType: GitTagsDatasource.id,
+        matchHost: 'github.com',
+        token: TOKEN_STRING,
+      });
+      expect(
+        findGithubPersonalAccessToken({
+          hostType: GitTagsDatasource.id,
+          url: 'https://github.com',
+        })
+      ).toBeUndefined();
+    });
+
+    it('returns undefined when no hostRule match search', () => {
+      expect(
+        findGithubPersonalAccessToken({
+          hostType: GitTagsDatasource.id,
+          url: 'https://github.com',
+        })
+      ).toBeUndefined();
+    });
+  });
+
+  describe('isPersonalAccessToken', () => {
+    it('returns true when string is a github personnal access token', () => {
+      expect(isPersonalAccessToken('ghp_XXXXXX')).toBeTrue();
+    });
+
+    it('returns false when string is a github application token', () => {
+      expect(isPersonalAccessToken('ghs_XXXXXX')).toBeFalse();
+    });
+
+    it('returns false when string is not a token at all', () => {
+      expect(isPersonalAccessToken('XXXXXX')).toBeFalse();
+    });
+  });
 });
diff --git a/lib/modules/manager/composer/utils.ts b/lib/modules/manager/composer/utils.ts
index 3571196ad30ae71abd787cdcc94c624bc9bcccb9..0657eb9c88a6a7f632a073de47153fe1cfc5ea8d 100644
--- a/lib/modules/manager/composer/utils.ts
+++ b/lib/modules/manager/composer/utils.ts
@@ -4,6 +4,8 @@ import { quote } from 'shlex';
 import { GlobalConfig } from '../../../config/global';
 import { logger } from '../../../logger';
 import type { ToolConstraint } from '../../../util/exec/types';
+import { HostRuleSearch, find as findHostRule } from '../../../util/host-rules';
+import { regEx } from '../../../util/regex';
 import { api, id as composerVersioningId } from '../../versioning/composer';
 import type { UpdateArtifactsConfig } from '../types';
 import type { ComposerConfig, ComposerLock } from './types';
@@ -109,3 +111,17 @@ export function extractConstraints(
   }
   return res;
 }
+
+export function findGithubPersonalAccessToken(
+  search: HostRuleSearch
+): string | undefined {
+  const token = findHostRule(search)?.token;
+  if (token && isPersonalAccessToken(token)) {
+    return token;
+  }
+  return undefined;
+}
+
+export function isPersonalAccessToken(token: string): boolean {
+  return regEx(/^ghp_/).test(token);
+}