Search code examples
typescripthttp-headersgithub-actionsaccess-tokengithub-api

How can I use the GitHub REST API to access a file's data in a private repository owned by an organization via my personal access token?


Problem

I am in charge of trying to retrieve the json data from a file in a private repository in my company's organization. I am an owner of the organization, but keep getting either a 404 or 401 error when using my personal access token generated from my GitHub account.

  • Why I can't use OAuth
    This node app is going to be used as a part of GH Actions in a repository, and a user won't be able to login to verify access at every push to the repository. Hence why I am looking for a solution using an access token of some sort.

Things I tried:

  • Reviewing other StackOverflow questions, all of which were either not relevant, not working, not answered, or were outdated.
  • I tried enabling all privileges for the access token. (the rest were done with all privileges enabled)
  • Switching between raw.githubusercontent.com and api.github.com, adding and removing the .raw part of the Accept header each time.
  • Using each URL with and without the Accept header.
  • Using Authorization: "token TOKEN" and Authorization: "Bearer TOKEN" with each URL.
  • Using a repository from my own account and that WORKS great with the access token I generated.

Code that I'm currently using

https
  .get(
    // "https://raw.githubusercontent.com/ORG_NAME/REPO_NAME/main/path/data.json", // results in 404 error
    "https://api.github.com/repos/ORG_NAME/REPO_NAME/contents/path/data.json", // results in 403 error
    {
      headers: {
        // request the v3 version of the api
        Accept: "application/vnd.github.v3.raw+json",
        "Content-Type": "application/json;charset=UTF-8",
        Authorization: `token ${process.env.GH_TOKEN}`,
      },
    },
    res => {
    const statusCode = res.statusCode;
    const contentType = res.headers["content-type"] || "";

    let error;
    if (statusCode !== 200) {
       error = new Error(
         "Request Failed.\n" +
           `Status Code: ${statusCode}: ${res.statusMessage}`
        );
    } else if (!/^application\/json/.test(contentType)) {
      error = new Error(
        "Invalid content-type.\n" +
          `Expected application/json but received ${contentType}`
      );
    }
    if (error) {
      console.log(error.message);
      // consume response data to free up memory
      res.resume();
      return;
    }

    res.setEncoding("utf8");
    let rawData = "";
    res.on("data", chunk => (rawData += chunk));
    res.on("end", () => {
      try {
        const parsedData = JSON.parse(rawData);
        console.log(parsedData);
      } catch (e) {
        if (e instanceof Error) console.log(e.message);
      }
    });
  })
.on("error", e => {
  console.log(`Got error: ${e.message}`);
});

Sort-of "working" but not ideal solution

What does work is using this URL: https://raw.githubusercontent.com/ORG_NAME/REPO_NAME/main/path/data.json?token=SOME_RANDOM_GENERATED_TOKEN, with the generated token being added after clicking the Raw button from the repo page. I don't want to use this token obviously for a production Action.

How can I get this to work? Is it even possible at this time?


Solution

  • I tried with below request and it works.

    GET 'https://raw.githubusercontent.com/ORG_NAME/REPO_NAME/main/README.md' \
     Authorization:'token <Personal Access Token>'
    

    Issue could be in request URL - Looks like you are including /path/ in request URL which is not required. You need to provide actual path of file, so correct URL will be

    https://raw.githubusercontent.com/ORG_NAME/REPO_NAME/main/data.json