rest.js: Cannot download private release asset

I am trying to download an asset from Github. Here is the corresponding code:

import Octokit from "@octokit/rest"
const octokit = new Octokit({
  auth: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
});
const owner = "Geode-solutions";
const repo = "opengeode";
const asset_id = 13450175;
octokit
  .request("GET /repos/:owner/:repo/releases/assets/:asset_id", {
      headers: {
         Accept: "application/octet-stream"
      },
      owner,
      repo,
      asset_id
});

I got this error in return:

OPTIONS https://github-production-release-asset-2e65be.s3.amazonaws.com/156866568/4524ae80-99ab-11e9-93db-8c3a783c062c?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20190702%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20190702T120659Z&X-Amz-Expires=300&X-Amz-Signature=65d90d511f7753dde757d77cab65ccea135868dce37c386e6fdb7a52c1ae813e&X-Amz-SignedHeaders=host&actor_id=3213882&response-content-disposition=attachment%3B%20filename%3DOpenGeode-1.5.16-Linux.tar.gz&response-content-type=application%2Foctet-stream 403 (Forbidden)

Access to fetch at 'https://github-production-release-asset-2e65be.s3.amazonaws.com/156866568/4524ae80-99ab-11e9-93db-8c3a783c062c?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20190702%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20190702T120659Z&X-Amz-Expires=300&X-Amz-Signature=65d90d511f7753dde757d77cab65ccea135868dce37c386e6fdb7a52c1ae813e&X-Amz-SignedHeaders=host&actor_id=3213882&response-content-disposition=attachment%3B%20filename%3DOpenGeode-1.5.16-Linux.tar.gz&response-content-type=application%2Foctet-stream' (redirected from 'https://api.github.com/repos/Geode-solutions/opengeode/releases/assets/13450175') from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

What do I have to add to my headers to make it works? Thanks for your help!

About this issue

  • Original URL
  • State: open
  • Created 5 years ago
  • Reactions: 9
  • Comments: 38 (15 by maintainers)

Most upvoted comments

Don’t expect this to be resolved anytime soon. I will update this issues as soon as there are any news.

Issue-Label Bot is automatically applying the label bug to this issue, with a confidence of 0.54. Please mark this comment with 👍 or 👎 to give our bot feedback!

Links: app homepage, dashboard and code for this bot.

Unfortunately no. The only thing you can do right now is to inform support@github.com that this is a blocking issue for you to bump the priority on the problem internally.

Hi, have you tried with:

request(
  {
    url:
      "https://api.github.com/repos/:owner/:repo/releases/assets/:asset_id",
    method: "GET",
    headers: {
      Accept: "application/octet-stream",
      Authorization: "token " + process.env.GITHUB_TOKEN,
      "User-Agent": "",
    },
  },
  function (error, response, body) {
    console.log(body);
  }
);

The body should contains the content of your asset.

You can do it also with curl:

curl -v -L -H 'Accept: application/octet-stream' -H 'Authorization: token YOUR_TOKEN' https://api.github.com/repos/:owner/:repo/releases/assets/:asset_id

Here is the magic required to stream release assets to a file using rest.js, typescript, and async/await:

import { Octokit } from "@octokit/rest";
import { createWriteStream } from "node:fs";
import { join } from "node:path";
import { pipeline } from "node:stream/promises";

async function fetchAsset() {
  const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
  const asset = await octokit.rest.repos.getReleaseAsset({
    owner: "foxglove",
    repo: "app",
    asset_id: 12345,
    headers: {
      accept: "application/octet-stream",
    },
    request: {
      parseSuccessResponseBody: false, // required to access response as stream
    },
  });

  const assetStream = asset.data as unknown as NodeJS.ReadableStream;
  const outputFile = createWriteStream(join("outputdir", "file.zip"));
  await pipeline(assetStream, outputFile);
}

You can also use

const requestOptions = octokit
  .request.endpoint("GET /repos/:owner/:repo/releases/assets/:asset_id", {
      headers: {
         Accept: "application/octet-stream"
      },
      owner,
      repo,
      asset_id
});

to get generic request options (except the authorization header), see https://github.com/octokit/endpoint.js. You can pass the requestOptions to axios or any custom request library.

Thanks @edospadoni for the hint!

For now, we have to download assets from private repos via plain HTTP calls outside Octokit. I use got for the HTTP call -

// TypeScript implementation:
import got from "got";
import { pipeline } from "stream";
import { createWriteStream } from "fs";
import { promisify } from "util";
const asyncPipeline = promisify(pipeline);

type TDownload = {
  owner: string;
  repo: string;
  assetId: number;
  toLocalFile: string;
  githubToken?: string;
};

export async function downloadGithubAsset(dl: TDownload) {
  const token = dl.githubToken || process.env.GITHUB_TOKEN;
  return asyncPipeline(
    got.stream(
      `https://api.github.com/repos/${dl.owner}/${dl.repo}/releases/assets/${dl.assetId}`,
      {
        method: "GET",
        headers: {
          Accept: "application/octet-stream",
          Authorization: `token ${token}`,
          "User-Agent": "",
        },
      }
    ),
    createWriteStream(dl.toLocalFile)
  );
}

I promise that as soon as there is an update I will post it here. For the time being, the best you can do is to contact support at https://support.github.com/contact and let them know about your use case. They are aware of the problem, but the more people report it and share their use cases, the higher the priority will get.

Thank you all for your patience and support

I’ll bring it up tomorrow in a meeting, I’ll keep you posted here.

Sorry, I’m not aware of any movement on this, unfortunately. Maybe @nickfloyd can check, but as this has been open for so long, I wouldn’t get my hopes up.

Looks like this does not throw an error

const assetUrl = https://api.github.com/repos/gr2m/octokit-rest.js-1417/releases/assets/13689345
const token = 'your token here'
const response = await fetch(`${assetUrl}?access_token=${token}`, {
  headers: {
    accept: 'application/octet-stream'
  },
  mode: 'no-cors'
})

but response.body is null. My understanding is that no-cors means you cannot get access to the returned data at all