<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rageeni Dawale</title>
    <description>The latest articles on DEV Community by Rageeni Dawale (@rageenidawale).</description>
    <link>https://dev.to/rageenidawale</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3790197%2Fd767c00c-3180-4557-8971-0a25ae1c6dab.png</url>
      <title>DEV Community: Rageeni Dawale</title>
      <link>https://dev.to/rageenidawale</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rageenidawale"/>
    <language>en</language>
    <item>
      <title>I Didn’t Want to Give Full GitHub Access — So I Built My Own LeetCode-to-GitHub Sync Chrome Extension</title>
      <dc:creator>Rageeni Dawale</dc:creator>
      <pubDate>Wed, 25 Feb 2026 12:17:33 +0000</pubDate>
      <link>https://dev.to/rageenidawale/i-didnt-want-to-give-full-github-access-so-i-built-my-own-leetcode-to-github-sync-chrome-5cgi</link>
      <guid>https://dev.to/rageenidawale/i-didnt-want-to-give-full-github-access-so-i-built-my-own-leetcode-to-github-sync-chrome-5cgi</guid>
      <description>&lt;p&gt;I was practicing problems on LeetCode, and one day I thought:&lt;/p&gt;

&lt;p&gt;What if my GitHub could reflect this automatically?&lt;/p&gt;

&lt;p&gt;Not just as code, but as visible consistency. The contribution graph, the repository history — it would show that I was actively solving problems and improving over time. Anyone visiting my GitHub profile could see my LeetCode work without me manually uploading each solution.&lt;/p&gt;

&lt;p&gt;The idea was simple: accepted submissions on LeetCode should automatically appear in GitHub.&lt;/p&gt;




&lt;h2&gt;
  
  
  The existing solutions didn’t feel right
&lt;/h2&gt;

&lt;p&gt;There are already Chrome extensions that do this. But when I looked into them, I noticed something that made me uncomfortable.&lt;/p&gt;

&lt;p&gt;Most of them required:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full read/write access to all my GitHub repositories&lt;/li&gt;
&lt;li&gt;Logging into my LeetCode account through the extension&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This felt like giving too much control to a third-party tool.&lt;/p&gt;

&lt;p&gt;Even if they were trustworthy, granting broad access when the extension only needed to write to a single repository didn’t feel right.&lt;/p&gt;

&lt;p&gt;So instead of using an existing tool, I decided to build my own.&lt;/p&gt;




&lt;h2&gt;
  
  
  The core idea: minimal permissions, maximum control
&lt;/h2&gt;

&lt;p&gt;I wanted an extension that would:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Detect accepted LeetCode submissions&lt;/li&gt;
&lt;li&gt;Read the solution directly from the page&lt;/li&gt;
&lt;li&gt;Push it to GitHub automatically&lt;/li&gt;
&lt;li&gt;Require access to only one repository&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And importantly, it should work without needing to log into LeetCode through the extension itself.&lt;/p&gt;

&lt;p&gt;LeetCode already displays the submitted solution in the browser. The extension simply reads the code from the page DOM — no login handling or unnecessary permissions required.&lt;/p&gt;

&lt;p&gt;For GitHub authentication, I used fine-grained personal access tokens. This allowed the extension to access only the repository I explicitly permitted, instead of requesting access to everything.&lt;/p&gt;

&lt;p&gt;This approach gave me precise control over what the extension could and could not access.&lt;/p&gt;




&lt;h2&gt;
  
  
  How the extension works
&lt;/h2&gt;

&lt;p&gt;The extension is built using Chrome Extension Manifest V3 and integrates with the GitHub REST API.&lt;/p&gt;

&lt;p&gt;When a submission is accepted on LeetCode, the extension:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Detects the accepted state&lt;/li&gt;
&lt;li&gt;Extracts the solution code and language&lt;/li&gt;
&lt;li&gt;Creates a properly named file&lt;/li&gt;
&lt;li&gt;Pushes it to the configured GitHub repository&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Solutions are organized by language, making the repository clean and easy to navigate.&lt;/p&gt;

&lt;p&gt;What I found most interesting was how different pieces came together — browser DOM access, extension architecture, and GitHub API integration — to automate something that was previously manual.&lt;/p&gt;




&lt;h2&gt;
  
  
  Challenges I faced while building it
&lt;/h2&gt;

&lt;p&gt;What sounded simple initially turned out to involve several practical challenges, especially since I didn’t have prior experience building Chrome extensions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reading code reliably from a dynamic editor
&lt;/h3&gt;

&lt;p&gt;LeetCode uses a browser-based editor where content is rendered dynamically.&lt;/p&gt;

&lt;p&gt;This meant I couldn’t just query the DOM once and assume the solution would be available. I had to ensure that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the submission was actually accepted&lt;/li&gt;
&lt;li&gt;the editor content was fully rendered&lt;/li&gt;
&lt;li&gt;the correct code and language were extracted&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Understanding how the editor updated the DOM was essential to making the extension reliable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Detecting accepted submissions at the right time
&lt;/h3&gt;

&lt;p&gt;Timing was another challenge.&lt;/p&gt;

&lt;p&gt;The extension needed to sync the solution only after it was accepted — not before, and not multiple times.&lt;/p&gt;

&lt;p&gt;If the extension ran too early, it could miss the correct state or extract incomplete information. This required carefully detecting when the accepted state was present.&lt;/p&gt;

&lt;h3&gt;
  
  
  Preventing duplicate uploads
&lt;/h3&gt;

&lt;p&gt;Another issue was avoiding duplicate uploads.&lt;/p&gt;

&lt;p&gt;If the page was refreshed or revisited, the extension might try to upload the same solution again.&lt;/p&gt;

&lt;p&gt;I had to ensure that the extension didn’t repeatedly sync the same submission, keeping the repository clean and accurate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extracting additional metadata like difficulty
&lt;/h3&gt;

&lt;p&gt;Extracting information like problem difficulty was less straightforward than expected.&lt;/p&gt;

&lt;p&gt;Since this data is part of the dynamically rendered page, it required careful inspection of the DOM structure to extract it reliably.&lt;/p&gt;

&lt;h3&gt;
  
  
  Learning Chrome Extension architecture and Manifest V3
&lt;/h3&gt;

&lt;p&gt;This was my first time working with Chrome extensions and Manifest V3.&lt;/p&gt;

&lt;p&gt;Manifest V3 uses service workers instead of persistent background scripts, which means everything is event-driven rather than continuously running.&lt;/p&gt;

&lt;p&gt;Understanding how content scripts, background service workers, and extension storage worked together took time, but it was one of the most valuable parts of the project.&lt;/p&gt;




&lt;h2&gt;
  
  
  Publishing it made it real
&lt;/h2&gt;

&lt;p&gt;Initially, this was just a personal tool.&lt;/p&gt;

&lt;p&gt;But later, I decided to publish it on the Chrome Web Store.&lt;/p&gt;

&lt;p&gt;Seeing it live felt different from pushing code to GitHub. It was no longer just a private experiment — it was something others could actually use.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I chose fine-grained tokens (for now)
&lt;/h2&gt;

&lt;p&gt;Right now, the extension uses fine-grained personal access tokens for GitHub authentication.&lt;/p&gt;

&lt;p&gt;This was a deliberate choice.&lt;/p&gt;

&lt;p&gt;As an MVP, this approach allowed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;limiting access to a single repository&lt;/li&gt;
&lt;li&gt;avoiding broad repository permissions&lt;/li&gt;
&lt;li&gt;keeping the architecture simple without requiring a backend server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A more complete solution would use GitHub Apps, which provide a better authentication flow and more structured permissions.&lt;/p&gt;

&lt;p&gt;That’s something I plan to explore in future versions.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I want to improve next
&lt;/h2&gt;

&lt;p&gt;There are several improvements I’d like to add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supporting historical LeetCode submissions&lt;/li&gt;
&lt;li&gt;Improving the authentication flow&lt;/li&gt;
&lt;li&gt;Moving to GitHub Apps for better permission handling&lt;/li&gt;
&lt;li&gt;Making the setup process more user-friendly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These changes would make the extension both more secure and easier to use.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this project mattered to me
&lt;/h2&gt;

&lt;p&gt;This started with a simple motivation: I wanted my GitHub to reflect the work I was already doing.&lt;/p&gt;

&lt;p&gt;But building it taught me much more than I expected.&lt;/p&gt;

&lt;p&gt;It helped me understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how browser extensions interact with web applications&lt;/li&gt;
&lt;li&gt;how to securely integrate with external APIs&lt;/li&gt;
&lt;li&gt;how to design tools with minimal permissions&lt;/li&gt;
&lt;li&gt;how to build and ship something end-to-end&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More importantly, it reinforced the idea that small personal frustrations can lead to meaningful projects.&lt;/p&gt;

&lt;p&gt;Sometimes the best projects come from solving your own problems.&lt;/p&gt;

&lt;p&gt;This was one of those projects.&lt;/p&gt;




&lt;h3&gt;
  
  
  If you're interested in the implementation, here's the source code:
&lt;/h3&gt;

&lt;p&gt;GitHub repository:&lt;br&gt;
&lt;a href="https://github.com/rageenidawale/linkcode-leetcode-github-sync" rel="noopener noreferrer"&gt;https://github.com/rageenidawale/linkcode-leetcode-github-sync&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Chrome Web Store:&lt;br&gt;
&lt;a href="https://chromewebstore.google.com/detail/linkcode-leetcode-github/dglnhlkedekgdkdpmjollhabaomlgalc" rel="noopener noreferrer"&gt;https://chromewebstore.google.com/detail/linkcode-leetcode-github/dglnhlkedekgdkdpmjollhabaomlgalc&lt;/a&gt;&lt;/p&gt;

</description>
      <category>github</category>
      <category>javascript</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
