Files
renovate/lib/util/http/auth.ts
T
Sergei Zharinov 0ae44810fc fix(http): detect x-access-token prefix before hostType-based auth branching (#42083)
* fix: Add `github-digest` to `GITHUB_API_USING_HOST_TYPES` list

* fix(http): detect x-access-token prefix before hostType-based auth branching

Moves GitHub App installation token detection (`x-access-token:` prefix)
before the hostType-based authorization chain in `applyAuthorization`.
This ensures correct `token` scheme auth for any GitHub-related hostType,
not only those listed in `GITHUB_API_USING_HOST_TYPES`.

* test(http/auth): add regression test for GitHub App token with non-listed hostType

* Fixes

* Fix tests
2026-03-24 17:11:56 +00:00

86 lines
2.8 KiB
TypeScript

import { isNonEmptyString } from '@sindresorhus/is';
import {
FORGEJO_API_USING_HOST_TYPES,
GITEA_API_USING_HOST_TYPES,
GITHUB_API_USING_HOST_TYPES,
GITLAB_API_USING_HOST_TYPES,
} from '../../constants/index.ts';
import type { GotOptions } from './types.ts';
export type AuthGotOptions = Pick<
GotOptions,
| 'hostType'
| 'headers'
| 'noAuth'
| 'context'
| 'token'
| 'username'
| 'password'
>;
export function applyAuthorization<GotOptions extends AuthGotOptions>(
inOptions: GotOptions,
): GotOptions {
const options: GotOptions = { ...inOptions };
if (isNonEmptyString(options.headers?.authorization) || options.noAuth) {
return options;
}
options.headers ??= {};
if (options.token) {
const authType = options.context?.authType;
if (authType) {
if (authType === 'Token-Only') {
options.headers.authorization = options.token;
} else {
options.headers.authorization = `${authType} ${options.token}`;
}
} else if (options.token.startsWith('x-access-token:')) {
// GitHub App installation token — prefix is set by the GitHub platform init
const appToken = options.token.replace('x-access-token:', '');
options.headers.authorization = `Bearer ${appToken}`;
} else if (
options.hostType &&
FORGEJO_API_USING_HOST_TYPES.includes(options.hostType)
) {
options.headers.authorization = `Bearer ${options.token}`;
} else if (
options.hostType &&
GITEA_API_USING_HOST_TYPES.includes(options.hostType)
) {
// Gitea v1.8.0 and later support `Bearer` as alternate to `token`
// https://github.com/go-gitea/gitea/pull/5378
options.headers.authorization = `Bearer ${options.token}`;
} else if (
options.hostType &&
GITHUB_API_USING_HOST_TYPES.includes(options.hostType)
) {
options.headers.authorization = `token ${options.token}`;
} else if (
options.hostType &&
GITLAB_API_USING_HOST_TYPES.includes(options.hostType)
) {
// GitLab versions earlier than 12.2 only support authentication with
// a personal access token, which is 20 characters long.
if (options.token.length === 20) {
options.headers['Private-token'] = options.token;
} else {
options.headers.authorization = `Bearer ${options.token}`;
}
} else {
options.headers.authorization = `Bearer ${options.token}`;
}
delete options.token;
} else if (options.password !== undefined) {
// Otherwise got will add username and password to url and header
const auth = Buffer.from(
`${options.username ?? ''}:${options.password}`,
).toString('base64');
options.headers.authorization = `Basic ${auth}`;
delete options.username;
delete options.password;
}
return options;
}