Validating API keys in ChatCraft!
Tags: opensource, chatgpt, javascript, react
Published: 2023-12-14 08:34:24

---
series: Contributing to ChatCraft
---

Picking up from my last post, I will show the progress I've made in my code contributions to [ChatCraft](https://github.com/tarasglek/chatcraft.org), a developer-oriented version of ChatGPT.

# Issue Link
https://github.com/tarasglek/chatcraft.org/issues/230

# Issue Description
Add validation for OpenRouter API key

![enter api key page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/arz72dcwnptat49epp8c.png)

---

# Identifying the file or area of code to work on

For this [issue](https://github.com/tarasglek/chatcraft.org/issues/230), since it is about validating the OpenRouter API key, I used VSCode's search to help me locate where to get started.

I searched the line `Please choose your API provider and enter your API Key below to get started!` in VSCode and was able to find the React form responsible for submitting the API key which is located in the `Instructions.tsx` file. 

![Instructions.tsx](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hvdwmwv9ex7u2428uvlk.png)

This form, upon submission, triggered a function called `handleApiKeySubmit`. To go to this function, I simply CTRL+clicked the function name in VSCode.

![handleApiKeySubmit](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/29xz60asfoikykpwpchu.png)

It was hard to figure out which function or if statement was supposed to be in charge of validating the API keys. After adding some console.log messages and testing each scenario (valid OpenAI key, invalid OpenAI key, valid OpenRouter key, invalid OpenRouter key), I determined the following:

- `validateOpenAiApiKey()` always returned for OpenRouter key no matter if it is valid or invalid
- `validateOpenAiApiKey()` only returned for OpenAI key when the key is valid, and threw when the key is invalid

Now I know that there is validation happening in the `validateOpenAiApiKey` function for OpenAI keys, and that is probably where the I need to add the validation for OpenRouter keys.

Investigating `validateOpenAiApiKey()` in `ai.ts`:

![validateOpenAiApiKey](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uvc7989tpconc7lm7uwg.png)

I had to google what `!!` means here - it converts an object to boolean. If `queryModels` threw, it would return `false`; otherwise it would return `true`.

Investigating `queryModels()` in `ai.ts`:

![queryModels](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uv0inmx1em0m7whpm3fh.png)

After adding some more console.log messages and re-testing the scenarios, I deduced that `for await (const page of openai.models.list())` would throw when the OpenAI key was invalid. For valid OpenAI keys, or a valid or invalid OpenRouter key, it would not throw.

Now I have ascertained that this is where I should add my validation code for OpenRouter keys.

---

# Using OpenRouter Limits API for key validation

Following the official OpenRouter [docs](https://openrouter.ai/docs#limits), I sent a GET request to to OpenRouter to check the rate limit or credits left on an API key. In theory, this request should also be able to help me to check whether an API key is valid or not.

```
const res = fetch("https://openrouter.ai/api/v1/auth/key", {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer ${apiKey}'
  },
});
```

To test my theory, I printed out the response using console.log

Response of entering valid key:
![success response](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/semaa2vg0q1od2xtxb3s.png)

Response of entering invalid key:
![failed respons](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mrf1p3ny4xcdcpk00tu6.png)

From these responses I could see that `res.ok` is `true` for valid OpenRouter api keys and `false` for invalid ones.

---

# Implementing my validation code

![validation code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5fuh0jbry5kwhk8wylfw.png)

---

# Testing

![testing](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iq3bx400642m39jo5w0n.png)

I did testing with both valid and invalid OpenRouter keys. I also did regression testing with OpenAI keys to ensure I did not affect existing validations for OpenAI. See [PR](https://github.com/tarasglek/chatcraft.org/pull/306) for all testing screenshots.

---

## Pull Request

{% embed https://github.com/tarasglek/chatcraft.org/pull/306 %}

I fixed prettier issues, pushed my code to my branch, and created a pull request with details of my changes and screenshots of my testing.

---

# Code review and fixes

![Code review](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mv0xy0p04vwcjqxd0kvq.png)

What I did was check if we are using OpenAI and in the else clause, added the validation for OpenRouter. However, the repo owner preferred for me to specifically check that we are using OpenRouter. I changed my code accordingly.

![code fix after review](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/th2qujxq6fjtlhaumehy.png)

Another code change I was asked to do was move the validation code out of the `queryModels()` function, since that function is specifically used by OpenAI. I created a new generic function `validateApiKey()` which validates validates both OpenAI and OpenRouter keys, by calling `validateOpenAiApiKey()` or `validateOpenRouterApiKey()` respectively. I moved my validation code out of `queryModels()` and into `validateOpenRouterApiKey()`.

![code change](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/838hrhw2l50i0vnuhj1m.png)

[Update] My [PR](https://github.com/tarasglek/chatcraft.org/pull/306) has been merged!

---

# Follow up issue

Next, I plan to follow up and work on a [related issue](https://github.com/tarasglek/chatcraft.org/issues/307) to clear stored API keys when the user changes their API provider in the User Settings.

![Clear key issue](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hwbnsplh0iez2x102dhe.png)

I was given a few choices on what the expected behaviour of this issue could be, and I decided to go with the easiest one, since I was low on time. When the user selects a different provider from the dropdown, we will clear the stored API key.

In the future, when I get more time, I would like to implement the functionality of being able to store both OpenRouter and OpenAI keys separately, with no need to clear it when we select a different provider.