How I built a small ReactJS app to automatically invite collaborators to a private GitHub repo 👌
Tags: javascript, react, webdev, node
Published: 2021-03-20 07:35:53

I currently maintain a GitHub repo called [react-coding-challenges](https://github.com/alexgurr/react-coding-challenges). It involves a variety of different difficulty challenges people can check out and complete. I also have a separate, private repository for the solutions to these challenges. The solutions are invite-only, meaning I need to invite each person as a collaborator before they get access (see the why [here](https://github.com/alexgurr/react-coding-challenges/#have-you-got-the-solutions)).

This was fine at the start, with a small amount of people requesting access. Now however, I have a steady stream of requests (usually via email which goes in to my spam folder) and it's becoming increasingly difficult/time consuming to manually do this process.

So what did I do? I built a MERN application that can automate this entire process with no-touch. Check it out at [solutions.alexgurr.com]
(https://solutions.alexgurr.com).

## How Does It Work?

### Client

#### The user clicks the main CTA button ![cta](https://puu.sh/HqNZP/27b3ab7547.png)
This uses a great library called [react-github-login](https://github.com/checkr/react-github-login).

```js
  import GitHubLogin from 'react-github-login';

  <GitHubLogin
    clientId="CLIENT_ID"
    onSuccess={joinRepo}
    onFailure={onFailure}
	
    // We only need the read:user scope to determine who the user is
    scope="read:user"
	
    // This is irrelevant because the auth window gets closed
    redirectUri=""
	
    // Use animate.css to give the button a pulse effect
    className={`button animate__animated animate__pulse animate__infinite animate__slow ${loading ? 'is-loading' : ''}`}
  >
    <div>
      <span className="icon">
        <i className="fab fa-github"></i>
      </span>
      <span>Let Me In</span>
    </div>
  </GitHubLogin>
```

&nbsp;
#### The library starts the GitHub OAuth login process and calls our callback with an oAuth code
```js
  const joinRepo = async ({ code }) => {
    try {
      // The code gets sent to the server
      await axios.post(config.serverUrl, { code });
  
      setJoined(true);
    } catch(e) {
      // if it's a 409, the user is already in the repository
      if (e.response && e.response.status && e.response.status === 409) {
        setAlreadyIn(true);

        return void setJoined(true);
      }

      toast("Oops, something went wrong.", { type: 'error', position: "bottom-left", hideProgressBar: true })
    }
  }
```

![success](https://puu.sh/HqO0e/1064f51099.png)

&nbsp;
### Server
#### Generate an access token for the user, using a client secret/id & the client code

```js
  const { data } = await axios.post('https://github.com/login/oauth/access_token', {
    client_id: 'ID',
    client_secret: 'SECRET',
    code: code
  });
```

&nbsp;
#### Retrieve the user's information using the generated access token

```js
  const { data: user } = await axios.get('https://api.github.com/user', {
    headers: { Authorization: `token ${data.split('&')[0].split('=')[1]}` }
  });
```

&nbsp;
#### Check if the user's a collaborator already
We use the `@octokit/rest` library for the more complex GitHub API actions, which is a node GitHub SDK

```js
  await octokit.repos.checkCollaborator({
    owner: GITHUB_UN,
    repo: 'react-coding-solutions',
    username
  });
```

If they are already a collaborator, we return at this point and return a response with 409 status code.

&nbsp;
#### Invite the user as a collaborator and return a success (201) response
```js
  await octokit.repos.addCollaborator({
    owner: GITHUB_UN,
    repo: 'react-coding-solutions',
    username
  });
```

&nbsp;
#### Store the user record in our database
We use [mongodb](https://www.mongodb.com) and [mongoose](https://github.com/Automattic/mongoose) as our user record store. This record write is **non-blocking** and we don't wait for it to finish before returning a response.

```js
  User.create({ username });
```

&nbsp;
&nbsp;
Overall, this was quite an easy app to build. I hope this gives some insight into how you could invite users to GitHub repos, or provide some inspiration to go and automate things!