Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
jaapvanblaaderen opened this issue Dec 3, 2021 · 1 comment
Labels
Type: Bug Something isn't working as documented

Comments

@jaapvanblaaderen
Copy link

jaapvanblaaderen commented Dec 3, 2021

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));
}
@jaapvanblaaderen jaapvanblaaderen added the Type: Bug Something isn't working as documented label Dec 3, 2021
@caglarturali
Copy link

caglarturali commented Dec 6, 2021

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.

I've been experiencing the same problem with Dart's http package for the last three days, and this part of your comment made my day :). For anyone looking for a workaround, here is what I did:

...

final Client _client = Client();

...

// Configure a request object to not to follow redirects and 'send' it
final request = Request('GET', ASSET_URI)
  ..followRedirects = false
  ..headers.addAll(YOUR_HEADERS);
final redirectResponse = await _client.send(request);

// Extract file location from headers
final location = redirectResponse.headers['location']!;

// Make the actual request for download
final response = await _client.get(Uri.parse(location));

...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Bug Something isn't working as documented
Projects
None yet
Development

No branches or pull requests

4 participants
@caglarturali @jaapvanblaaderen and others