Skip to content

Unable to download release asset: "Multiple auth mechanisms are not allowed" #415

@jaapvanblaaderen

Description

@jaapvanblaaderen

What happened?

I use Octokit to download GitHub releases, this worked fine for months but suddenly stopped working as of today, with the following error:

HttpError: <Error><Code>AccessDenied</Code><Message>Multiple auth mechanisms are not allowed; please use either query parameters or an Authorization header</Message>

This is the function I use to download the release:

async function downloadRelease(destination: string, token: string, owner: string, repo: string, assetName: string) {
    const octokit = new Octokit({
        auth: token,
    });
    const release = await octokit.request('GET /repos/{owner}/{repo}/releases/{asset_id}', {
        owner: owner,
        repo: repo,
        asset_id: 'latest',
    });
    const asset = await octokit.request(release.data.assets_url);
    const assetData = (asset.data as { name: string; url: string }[]).find((assetData) => assetData.name === assetName);
    if (!assetData) {
        throw new Error(`Unable to find ${assetName}`);
    }
    const res = await octokit.request(assetData.url, {
        headers: { accept: 'application/octet-stream' },
    });
    await fs.promises.writeFile(destination, Buffer.from(res.data));
}

The part that fails is the actual download of the file:

 const res = await octokit.request(assetData.url, {
      headers: { accept: 'application/octet-stream' },
 });

What did you expect to happen?

Octokit to properly download the release asset as described in the docs: https://docs.github.com/en/rest/reference/repos#get-a-release-asset

What the problem might be

I assume that something changed in the GitHub API making authorization stricter? When downloading the file, GitHub redirects to another url. This redirected URL contains authentication information. I guess that Octokit then uses this URL but still also includes the authorization header containing the personal access token. This combination results in a failure.

Example of requested file:

https://api.github.com/repos/owner/repo/releases/assets/1234

Example of the URL containing credentials it redirects to (simplified/shortened):

https://objects.githubusercontent.com/github-production-release-asset-abc/1234-5678?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...

I can actually get it to work when rewriting the download part of my function using an external http library (I used got):

async function downloadRelease(destination: string, token: string, owner: string, repo: string, assetName: string) {
    const octokit = new Octokit({
        auth: token,
    });
    const release = await octokit.request('GET /repos/{owner}/{repo}/releases/{asset_id}', {
        owner: owner,
        repo: repo,
        asset_id: 'latest',
    });
    const asset = await octokit.request(release.data.assets_url);
    const assetData = (asset.data as { name: string; url: string }[]).find((assetData) => assetData.name === assetName);
    if (!assetData) {
        throw new Error(`Unable to find ${assetName}`);
    }
    const file = (
        await got(assetData.url, {
            method: 'GET',
            headers: {
                authorization: `token ${token}`,
                accept: 'application/octet-stream',
            },
        })
    ).rawBody;
    await fs.promises.writeFile(destination, Buffer.from(file));
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type: BugSomething isn't working as documented

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions