diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0ff3741..68ffb34 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,8 +9,9 @@
 - Fix: Rename and organize `clean.py` module into `utils_parse` and `utils_clean` (@lwasser, @willingc, #121)
 - Fix: Add tests for all utils functions (@lwasser, #122)
 - Fix: Bug where date_accepted is removed (@lwasser, #129)
-- Fix: Refactor all GitHub related methods move to gh_client module (@lwasser, #125)
+- Fix: Refactor all issue related GitHub methods to gh_client module (@lwasser, #125)
 - Add: support for partners and emeritus_editor in contributor model (@lwasser, #133)
+- Fix: Refactor all contributor GitHub related methods into gh_client module from contributors module (@lwasser, #125)
 
 
 ## [v0.2.3] - 2024-02-29
diff --git a/pyproject.toml b/pyproject.toml
index 928660e..9b5c679 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -69,7 +69,7 @@ version.source = "vcs"
 build.hooks.vcs.version-file = "src/pyosmeta/_version.py"
 
 [tool.hatch.envs.test]
-dependencies = ["pytest", "pytest-cov", "coverage[toml]"]
+dependencies = ["pytest", "pytest-cov", "coverage[toml]", "pytest-mock"]
 
 [tool.hatch.envs.test.scripts]
 run-coverage = "pytest --cov-config=pyproject.toml --cov=pyosmeta --cov=tests/*"
diff --git a/src/pyosmeta/cli/update_contributors.py b/src/pyosmeta/cli/update_contributors.py
index 1655fd0..1066a59 100644
--- a/src/pyosmeta/cli/update_contributors.py
+++ b/src/pyosmeta/cli/update_contributors.py
@@ -6,6 +6,7 @@
 
 from pyosmeta.contributors import ProcessContributors
 from pyosmeta.file_io import create_paths, load_pickle, open_yml_file
+from pyosmeta.github_api import GitHubAPI
 from pyosmeta.models import PersonModel
 
 # TODO - https://stackoverflow.com
@@ -62,7 +63,8 @@ def main():
     print("Done processing all-contribs")
 
     # Create a list of all contributors across repositories
-    process_contribs = ProcessContributors(json_files)
+    github_api = GitHubAPI()
+    process_contribs = ProcessContributors(github_api, json_files)
     bot_all_contribs = process_contribs.combine_json_data()
 
     print("Updating contrib types and searching for new users now")
@@ -71,7 +73,7 @@ def main():
             # Find and populate data for any new contributors
             if gh_user not in all_contribs.keys():
                 print("Missing", gh_user, "Adding them now")
-                new_contrib = process_contribs.get_user_info(gh_user)
+                new_contrib = process_contribs.return_user_info(gh_user)
                 new_contrib["date_added"] = datetime.now().strftime("%Y-%m-%d")
                 all_contribs[gh_user] = PersonModel(**new_contrib)
 
@@ -81,7 +83,7 @@ def main():
     if update_all:
         for user in all_contribs.keys():
             print("Updating all user info from github", user)
-            new_gh_data = process_contribs.get_user_info(user)
+            new_gh_data = process_contribs.return_user_info(user)
 
             # TODO: turn this into a small update method
             existing = all_contribs[user].model_dump()
diff --git a/src/pyosmeta/contributors.py b/src/pyosmeta/contributors.py
index c2903b9..6362bbd 100644
--- a/src/pyosmeta/contributors.py
+++ b/src/pyosmeta/contributors.py
@@ -1,10 +1,10 @@
 import json
-import os
 
 import requests
 from dataclasses import dataclass
-from dotenv import load_dotenv
-from typing import List, Optional, Tuple
+from typing import Any, List, Optional, Tuple
+
+from .github_api import GitHubAPI
 
 
 @dataclass
@@ -12,20 +12,20 @@ class ProcessContributors:
     """A class that contains some basic methods to support populating and
     updating contributor data."""
 
-    def __init__(self, json_files: List) -> None:
+    def __init__(self, github_api: GitHubAPI, json_files: List) -> None:
         """
         Parameters
         ----------
-
+        github_api : str
+            Instantiated instance of a GitHubAPI object
         json_files : list
             A list of string objects each of which represents a URL to a JSON
             file to be parsed
-        GITHUB_TOKEN : str
-            A string containing your API token needed to access the github API
         """
 
+        self.github_api = github_api
         self.json_files = json_files
-        # self.GITHUB_TOKEN = GITHUB_TOKEN
+
         self.update_keys = [
             "twitter",
             "website",
@@ -52,18 +52,6 @@ def __init__(self, json_files: List) -> None:
             ],
         }
 
-    def get_token(self) -> str:
-        """Fetches the GitHub API key from the users environment. If running
-        local from an .env file.
-
-        Returns
-        -------
-        str
-            The provided API key in the .env file.
-        """
-        load_dotenv()
-        return os.environ["GITHUB_TOKEN"]
-
     def check_contrib_type(self, json_file: str):
         """
         Determine the type of contribution the person
@@ -94,6 +82,7 @@ def check_contrib_type(self, json_file: str):
             contrib_type = "community"
         return contrib_type
 
+    # Possibly github it is a get request but it says json path
     def load_json(self, json_path: str) -> dict:
         """
         Helper function that deserializes a json file to a dict.
@@ -153,9 +142,9 @@ def combine_json_data(self) -> dict:
                 print("Oops - can't process", json_file, e)
         return combined_data
 
-    def get_user_info(
-        self, username: str, aname: Optional[str] = None
-    ) -> dict:
+    def return_user_info(
+        self, gh_handle: str, name: Optional[str] = None
+    ) -> dict[str, Any]:
         """
         Get a single user's information from their GitHub username using the
         GitHub API
@@ -163,9 +152,9 @@ def get_user_info(
 
         Parameters
         ----------
-        username : string
+        gh_handle : string
             Github username to retrieve data for
-        aname : str default=None
+        name : str default=None
             A user's name from the contributors.yml file.
             https://docs.github.com/en/rest/users/users?apiVersion=2022-11-28#get-a-user
 
@@ -174,14 +163,8 @@ def get_user_info(
             Dict with updated user data grabbed from the GH API
         """
 
-        url = f"https://api.github.com/users/{username}"
-        headers = {"Authorization": f"Bearer {self.get_token()}"}
-        response = requests.get(url, headers=headers)
-        # TODO: add check here for if credentials are bad
-        # if message = Bad credentials
-        response_json = response.json()
+        response_json = self.github_api.get_user_info(gh_handle, name)
 
-        # TODO: make an attribute and call it here?
         update_keys = {
             "name": "name",
             "location": "location",
diff --git a/src/pyosmeta/file_io.py b/src/pyosmeta/file_io.py
index d747ab5..18a2373 100644
--- a/src/pyosmeta/file_io.py
+++ b/src/pyosmeta/file_io.py
@@ -29,16 +29,24 @@ def _list_to_dict(a_list: List, a_key: str) -> Dict:
 
 
 def create_paths(repos: Union[list[str], str]) -> Union[list[str], str]:
-    """ """
+    """Construct URLs for .all-contributorsrc file on GitHub for pyos repos.
+
+    We add new contributors to each repo using the all contributors bot. This
+    generates urls for all of the files across all of our repos where people
+    contribute to our content and processes.
+
+    Parameters:
+    ----------
+    repos : Union[List[str], str]
+        A list of GitHub repository names or a single repository name.
+
+    Returns:
+    -------
+    Union[List[str], str]
+        A list of URLs if `repos` is a list, or a single URL if `repos` is a string.
+    """
     base_url = "https://raw.githubusercontent.com/pyOpenSci/"
     end_url = "/main/.all-contributorsrc"
-    repos = [
-        "python-package-guide",
-        "software-peer-review",
-        "pyopensci.github.io",
-        "software-review",
-        "update-web-metadata",
-    ]
     if isinstance(repos, list):
         all_paths = [base_url + repo + end_url for repo in repos]
     else:
diff --git a/src/pyosmeta/github_api.py b/src/pyosmeta/github_api.py
index 789d0c8..fb29338 100644
--- a/src/pyosmeta/github_api.py
+++ b/src/pyosmeta/github_api.py
@@ -15,7 +15,7 @@
 import requests
 from dataclasses import dataclass
 from dotenv import load_dotenv
-from typing import Any
+from typing import Any, Optional, Union
 
 
 @dataclass
@@ -224,3 +224,34 @@ def get_last_commit(self, repo: str) -> str:
         date = response[0]["commit"]["author"]["date"]
 
         return date
+
+    def get_user_info(
+        self, gh_handle: str, name: Optional[str] = None
+    ) -> dict[str, Union[str, Any]]:
+        """
+        Get a single user's information from their GitHub username using the
+        GitHub API
+        # https://docs.github.com/en/rest/users/users?apiVersion=2022-11-28#get-the-authenticated-user
+
+        Parameters
+        ----------
+        gh_handle : string
+            Github username to retrieve data for
+        name : str default=None
+            A user's name from the contributors.yml file.
+            https://docs.github.com/en/rest/users/users?apiVersion=2022-11-28#get-a-user
+
+        Returns
+        -------
+            Dict with updated user data grabbed from the GH API
+        """
+
+        url = f"https://api.github.com/users/{gh_handle}"
+        headers = {"Authorization": f"Bearer {self.get_token()}"}
+        response = requests.get(url, headers=headers)
+
+        if response.status_code == 401:
+            raise ValueError(
+                "Oops, I couldn't authenticate. Please check your token."
+            )
+        return response.json()
diff --git a/tests/conftest.py b/tests/conftest.py
index 4a8f2ac..995191c 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,11 +1,42 @@
 import pytest
 
+from pyosmeta.contributors import ProcessContributors
 from pyosmeta.github_api import GitHubAPI
 from pyosmeta.parse_issues import ProcessIssues
 
 
+@pytest.fixture
+def ghuser_response():
+    """This is the initial github response. I changed the username to
+    create this object"""
+    expected_response = {
+        "login": "chayadecacao",
+        "id": 123456,
+        "node_id": "MDQ6VXNlcjU3ODU0Mw==",
+        "avatar_url": "https://avatars.githubusercontent.com/u/123456?v=4",
+        "gravatar_id": "",
+        "url": "https://api.github.com/users/cacao",
+        "html_url": "https://github.com/cacao",
+    }
+    return expected_response
+
+
+@pytest.fixture
+def mock_github_api(mocker, ghuser_response):
+    mock_api = mocker.Mock(spec=GitHubAPI)
+    mock_api.get_user_info.return_value = ghuser_response
+    return mock_api
+
+
+@pytest.fixture
+def process_contribs(contrib_github_api):
+    """A fixture that creates a"""
+    return ProcessContributors(contrib_github_api)
+
+
 @pytest.fixture
 def github_api():
+    """A fixture that instantiates an instance of the GitHubAPI object"""
     return GitHubAPI(
         org="pyopensci", repo="pyosmeta", labels=["label1", "label2"]
     )
diff --git a/tests/unit/test_contributors_module.py b/tests/unit/test_contributors_module.py
new file mode 100644
index 0000000..22d387f
--- /dev/null
+++ b/tests/unit/test_contributors_module.py
@@ -0,0 +1,27 @@
+from pyosmeta.contributors import ProcessContributors
+from pyosmeta.github_api import GitHubAPI
+
+
+def test_init(mocker):
+    """Test that the ProcessContributors object instantiates as
+    expected"""
+
+    # Create a mock GitHubAPI object
+    github_api_mock = mocker.MagicMock(spec=GitHubAPI)
+    json_files = ["file1.json", "file2.json"]
+
+    process_contributors = ProcessContributors(github_api_mock, json_files)
+
+    assert process_contributors.github_api == github_api_mock
+    assert process_contributors.json_files == json_files
+
+
+def test_return_user_info(mock_github_api, ghuser_response):
+    """Test that return from github API user info returns expected
+    GH username."""
+
+    process_contributors = ProcessContributors(mock_github_api, [])
+    gh_handle = "chayadecacao"
+    user_info = process_contributors.return_user_info(gh_handle)
+
+    assert user_info["github_username"] == gh_handle
diff --git a/tests/unit/test_github_api.py b/tests/unit/test_github_api.py
index 2e17e99..783056a 100644
--- a/tests/unit/test_github_api.py
+++ b/tests/unit/test_github_api.py
@@ -51,3 +51,31 @@ def test_api_endpoint(github_api):
         "issues?labels=label1,label2&state=all&per_page=100"
     )
     assert github_api.api_endpoint == expected_endpoint
+
+
+def test_get_user_info_successful(mocker, ghuser_response):
+    """Test that an expected response returns properly"""
+
+    expected_response = ghuser_response
+    mock_response = mocker.Mock()
+    mock_response.status_code = 200
+    mock_response.json.return_value = expected_response
+    mocker.patch("requests.get", return_value=mock_response)
+
+    github_api_instance = GitHubAPI()
+    user_info = github_api_instance.get_user_info("example_user")
+
+    assert user_info == expected_response
+
+
+def test_get_user_info_bad_credentials(mocker):
+    """Test that a value error is raised when the GH token is not
+    valid."""
+    mock_response = mocker.Mock()
+    mock_response.status_code = 401
+    mocker.patch("requests.get", return_value=mock_response)
+
+    github_api = GitHubAPI()
+
+    with pytest.raises(ValueError, match="Oops, I couldn't authenticate"):
+        github_api.get_user_info("example_user")