Can I modify repository files using pure JavaScript and GitHub API without external libraries

I need to update files in my public GitHub repo directly from a web page using only vanilla JavaScript. No external libraries like octokit allowed. I want to modify a JSON file in my repository through the GitHub API.

I already have my personal access token and client credentials set up. GitHub documentation mostly shows octokit examples, but since they only “recommend” it, there should be other ways to do this with plain JavaScript.

I tried something like this but it didn’t work:

let appId = "MY_APP_ID";
let accessToken = "PERSONAL_ACCESS_TOKEN";

fetch(`https://api.github.com/repos/username/repo-name/data.json?client_id=${appId}&access_token=${accessToken}`, {
    method: "POST",
    headers: { 'Content-Type': 'application/json'},
    body: JSON.stringify('New content for the file')
}).then(res => {
    console.log("Done! Response:", res);
});

After some testing, I found a working solution that doesn’t have CORS issues even from localhost. Here’s what worked:

// Configuration
const repoOwner = "myUsername";
const repoName = "myProject";
const filePath = "data.json";
const authToken = "ghp_tokenhere";

// Content to write
const fileContent = {
  name: "Product Name",
  category: "Electronics", 
  cost: 199.99
};

// Get current file SHA
async function getCurrentSha() {
  try {
    const response = await fetch(
      `https://api.github.com/repos/${repoOwner}/${repoName}/contents/${filePath}`,
      {
        method: "GET",
        headers: {
          "Authorization": `Bearer ${authToken}`,
          "Accept": "application/vnd.github+json",
          "Content-Type": "application/json"
        }
      }
    );
    
    if (!response.ok) {
      if (response.status === 404) return null;
      throw new Error(`Error getting SHA: ${response.statusText}`);
    }
    
    const fileData = await response.json();
    return fileData.sha;
  } catch (err) {
    console.error("SHA fetch error:", err);
    return null;
  }
}

// Update file content
async function modifyRepoFile() {
  try {
    const currentSha = await getCurrentSha();
    const encodedContent = btoa(JSON.stringify(fileContent, null, 2));
    
    const requestBody = {
      message: "Updated data.json from web interface",
      content: encodedContent,
      sha: currentSha
    };
    
    const response = await fetch(
      `https://api.github.com/repos/${repoOwner}/${repoName}/contents/${filePath}`,
      {
        method: "PUT",
        headers: {
          "Authorization": `Bearer ${authToken}`,
          "Accept": "application/vnd.github+json",
          "Content-Type": "application/json"
        },
        body: JSON.stringify(requestBody)
      }
    );
    
    if (!response.ok) {
      const errorInfo = await response.json();
      throw new Error(`Update failed: ${errorInfo.message}`);
    }
    
    const updateResult = await response.json();
    console.log("Success! Commit link:", updateResult.commit.html_url);
  } catch (err) {
    console.error("File update error:", err);
  }
}

modifyRepoFile();

This approach works perfectly with just vanilla JavaScript and no external dependencies.

heads up - btoa() will break if your file content has unicode characters. hit this bug when updating config files with special characters in usernames. btoa only works with latin-1, so anything else throws errors. use btoa(unescape(encodeURIComponent(content))) for proper utf-8 encoding, or TextEncoder if you don’t need IE support.

Your solution covers the basics well, but you’ve got a token security problem. Personal access tokens in browser JavaScript are visible to anyone who checks page source or network requests. Hit this exact issue on a client project last year. Even with public repos, exposed tokens let attackers mess with your entire GitHub account. GitHub catches leaked tokens in commits but can’t spot browser exposure. For production, set up a backend proxy that keeps the token server-side. Your frontend hits your own API, which talks to GitHub. Keeps credentials safe while your client stays vanilla JavaScript. Better yet, use GitHub Apps with fine-grained permissions instead of personal tokens. They limit access to specific repos and actions, so less damage if someone gets hold of them.

Yes, totally possible and your solution looks solid. I’ve done similar stuff for automated content management and this approach works reliably.

One thing I learned the hard way - always add proper error handling for rate limiting. GitHub’s API limits you to 5000 requests per hour for authenticated requests. You’ll get HTTP 403 responses when you hit that limit. I usually throw in a simple retry mechanism with exponential backoff for production.

Your Bearer token approach is spot on - it’s the current recommended method. That old ?access_token= query parameter you tried first got deprecated in 2021, which is why it failed.

For production, consider adding token refresh logic if this’ll get heavy use. Personal access tokens don’t auto-expire, but rotating them periodically is good practice. GitHub’s API gives clear error messages when tokens go invalid, so debugging’s pretty straightforward.

Nice work getting that vanilla JS solution running! I’ve struggled with the GitHub API too.

Your approach works, but I’d automate this instead of handling it manually in the browser. Running file updates from web pages gets messy when you scale or add complex logic.

I built something similar with Latenode recently - it handles GitHub file updates way better. You can trigger workflows with webhooks, schedule updates, or connect forms to automatically push repo changes. It handles SHA fetching and error handling for you.

You also get retry logic, rate limit handling, and can chain operations like notifications or batch file updates. Much cleaner than managing browser JavaScript state.

For your case, create an HTTP endpoint that takes JSON data and pushes to GitHub. Your web page just makes one API call instead of dealing with tokens and encoding.

Check it out: https://latenode.com