In the next few chapters, we're going to go over what's left to do in our project before we can deploy. And the way we can do that is by easily searching for the word TODO. And everywhere where we have a TODO is probably something we should take a look before deploying. And one that's quite obvious is the credential value, which is currently stored as a plain text, both in the create procedure and in the update procedure right here. I still stand by what I said when we developed this.
The best solution to encrypt this would be by using a third-party service such as AWS Secrets Manager. But there is a thing we can do which isn't a third party service. It's way simpler than AWS Secrets Manager and it is marginally better than just storing the value as plain text in your database. That being said, it's also not perfect. So that's what I want to do in this chapter.
I want to not store plain text strings when it comes to users' credentials. And then we're going to go ahead and look for other to-dos that we have. And no, I did not forget about Google and GitHub sign in that's also in our to do's. So for this chapter I want to focus on encrypting our credentials. The way we're going to do that is by using Crypter, an npm package.
So let's do npm install crypto. Let's go ahead and open package adjacent and you can see the version 6.4.0. You don't have to use the same version, I just want to make sure you are aware of my versions. Let's go ahead and set up .environment file. Let's create encryption section here and let's add encryption key.
Now in here you would use something to generate this key. You can use 1Password, LastPass or a million services on Google when you search for encryption key generator. For development you can just put my secure key. In production please do not use that, please put something secure here because if someone else can guess this key they can easily decrypt all of the values in your database. So once you have encryption key ready, let's go ahead and do the following.
We're going to go inside of source, lib, and in here we're going to create encryption.ts. Like this. Inside of encryption.ts file, let's go ahead and add the following code. Import crypto from crypto. Const crypto will be new crypto process dot environment and then go ahead and use the encryption key that you've added here.
I always recommend that you copy and paste from your environment variables So you don't accidentally misspell any words. Then let's go ahead and export const encrypt by using a function which accepts a string and simply returns the result of crypto.encrypt and pass in the string. And the exact same process is for decrypt. Let me just go ahead and fix this decrypt and decrypt. There we go.
Now that we have this ready, let's go ahead and find our credentials routers. So inside of our credentials router here, let's find create, which is a premium procedure. And let's go ahead and remove this. And let's use encrypt from lib encryption value. There we go.
So just make sure you've added encrypt here. And same thing is true in update here. So you can remove this, encrypt, value. There we go. So that's it for storing into our database.
What we have to do now is we have to revisit all the places where we use this value. So that is inside of execution components. So let's open Anthropic Executor. Let's go ahead and open Gemini Executor. And let's go ahead and open OpenAI Executor.
So right now all of these will fail because when we store a new credential, it will, let me show you actually how it looks like. Yes, so here is the Cryptr npm package. If you want to encrypt the word bacon, this is what will be stored in our database so this huge hash and then later when we decrypt it it's going to be back to bacon so if we tried using our API keys right now they would all fail because they are encrypted in our database. So we now have to decrypt them. Let's go ahead and once we find the credential, so it doesn't matter what executor you are in, you have to do all three of them.
So let me start with Gemini one, Gemini folder executor.ts. And here it is. Once we add credential.value, let's simply go ahead and do decrypt like this and import decrypt from lib encryption. That's it for Gemini. Then let's go inside of open AI folder executor.
And let's do the same thing here. Decrypt from lib encryption. Make sure you've imported it. And Entropic is left. So again, decrypt.
Like that. Perfect. And I think that is all we need really. So if I search for to do now, there we go. And yeah, I have this to do instead of that.
So this is completely off topic. But if I search for to do, I have this one, which is inside of my HTTP request dialog dot dsx. Instead of source features, executions, components, HTTP request dialog. We actually don't need to do this. I used to think that this would be a good idea like to validate if user's JSON is correct but that would defeat the purpose of our templating availability.
It's the same problem we had with endpoints being z.url and then it would break if you want to add a variable. So because of that I'm going to remove this. We're not going to solve that because we don't need it. So the only one that's actually left here besides GitHub and Google login is retries, which is still very useful for us in development at the moment. So let's leave it like this.
All right. So what to do now when this is done? Well, first things first, your credentials will no longer work because these are now completely broken. So what I suggest is you go ahead and delete these. And let's go ahead and create a new credential this time.
And let's go ahead and do npx prisma studio. So this should fire up the studio. And let's go ahead and find the credential here. So no credentials. Great.
And now I'm going to do encrypted Gemini. Gemini like this. And since I still have it in my dot environment here, I'm just going to copy it. This is why I told you to leave it here because you will still need it in the tutorial. So let me just add it here.
Okay. And I will click create. Looks like it was created successfully. And now inside of Prisma Studio, I'm going to refresh here. And let's see if this is working or not.
So what I'm expecting here is to see a completely different value. Let me just do a refresh one more time. It's fetching rows in this table. Basically, my Google generative AI API key starts with AI. I think that's an accident.
But you can see that my value is something completely different. So if someone were to break into my database, they would not be able to see users API keys, they would just be able to see this. Again, this is not the most perfect solution in the world. There's a lot of things missing like key rotation. And I would recommend solving this by adding a third-party library like AWS Secrets Manager.
But this is insanely better than just storing plain text inside of here, right? Just make sure you're using a good secret and that you never leak it because this is type of encryption that can be obviously decrypted which makes it very well dangerous to access if someone gets ahead of your encryption key. Great so you can see the value is completely different than what I've entered here and now we have to test if that works. So I'm going to go inside of my workloads, I'm going to create a completely new one and I'm just going to add a manual executor here And I'm going to connect it with a Gemini. Like this.
Let me open this, my Gemini, select a credential, encrypted Gemini, test, hello world. Let's click save, let's click save up there. And let's click execute workflow. And let's see if this will work. That succeeds and let's see this seems to succeed as well.
Let's go inside of executions right here. Less than a minute ago. So that should be the one. There we go. Hello world.
How can I help you today? Amazing. So it is successfully working. We have encrypted our values. Amazing job.
So since this was super simple change we don't have to really review this code. Instead we can go ahead and focus on the next chapter where we are going to be adding GitHub and Google sign in which is also going to be super simple. So just for you know keeping track of everything I'm going to create a new branch 28 encrypting credentials. Then I'm going to go ahead and add all of my changes here. Let me just expand this so I can expand this.
I'm staging all of my changes, 28 encrypting credentials. I'm going to commit and I'm going to publish the branch. And as I said, since this one is particularly simple, I'm just going to open a pull request and I am immediately going to merge it. So let's go ahead and confirm merge. After I've done that, I'm going to go ahead and go back instead of my main branch.
I'm going to click down here, synchronize changes, and I'm going to click OK. I'm going to open my graph and just confirm that I have a new Merge Pool 28 encrypting credentials. Great! I believe that marks the end of this chapter. And we just improved our app by a lot, right?
So it went from being barely recommended by anyone security wise to at least not storing plain text values. But again, please explore AWS Secrets Manager or look at my previous project if you are interested in key rotation and how this would look with a very good security system in place. But this is very, very good. And again, API keys are not exactly passwords. They can always be rotated, but you should provide your users who are trusting you with their API keys with maximum security that you can afford.
Excellent. And we pushed to GitHub. Amazing, amazing job and see you in the next chapter.