
No Comments Yet
Be the first to share your thoughts and start the conversation.
Be the first to share your thoughts and start the conversation.
👉 Bunny (create your free account and get one extra free month): https://jsm.dev/jsm-bunny
How did you manage to remove the blur property and reach here?
Upgrading gives you access to quizzes so you can test your knowledge, track progress, and improve your skills.
By logging in, you'll unlock full access to this and other free tutorials on JSM Pro.
Why? Logging in lets us personalize your learning experience, track your progress, and keep you in the loop with new workshops, coding tips, and platform updates.
You'll also be the first to know about upcoming launches, events, and exclusive discounts.
No spam—just helpful content to level up your skills.
If that sounds fair, go ahead and log in to continue →
Enter your name and email to get instant access
In this lesson, we focus on utilizing ArcJet to enhance the security of our application against various threats, including bot attacks and malicious users. We go through the steps of implementing measures such as bot detection, rate limiting, email validation, and overall protection against common web application vulnerabilities. The process covers installation, configuration, and practical application within our codebase.
00:00:02 To make our app more secure, we'll use Artjet.
00:00:05 We'll use it to detect bots that want to do harm on our website.
00:00:09 We'll use it to rate limit malicious users.
00:00:12 We'll use it for email validation so that users that try to log in with some spammy emails cannot get through, and we'll use it to protect against attacks.
00:00:21 I'll teach you how to implement all of this within this application, so you can secure your every future application from now on.
00:00:28 So just click the link down in the description, and then sign up for free.
00:00:31 Choose your provider, and you'll be redirected to your dashboard.
00:00:35 As you can see, I already used Artjet on our previous project called the Subscription Tracker, but now I'll create a new site.
00:00:42 You can give it a name, something like JSM underscore Snapcast, and click Create, and you can choose Next.js as our platform.
00:00:51 Then click continue with Next.js and you'll be redirected to the docs page.
00:00:57 First things first, we have to install ArcGit.
00:00:59 So just run this command that is npm i at ArcGit forward slash next and at ArcGit forward slash inspect.
00:01:07 While those are installing, you'll have to set up your ENVs.
00:01:11 So head over into your ENVs, create a new one for ArcGit and call it ArcGit.
00:01:19 And make it equal to the key, which we can get right here from our dashboard.
00:01:26 So click create a free account, which will redirect you to the dashboard.
00:01:31 And then right here at the top, you can get your API key.
00:01:35 So copy it and paste it right here.
00:01:38 Once that is done, we don't have to follow the documentation, as I'll teach you how to set it up from scratch.
00:01:44 First things first, we'll create a new file within the lib folder, which I'll call ArcGit.ts.
00:01:52 Within it, we want to create a new single instance of the ArcJet object, and we want to reuse it throughout the rest of the application.
00:02:00 This is because the SDK caches decisions and configurations to improve performance.
00:02:06 So from here, I will import ArcJet from at ArcJet forward slash next, And then we can simply say const aj, as in ArcJet,
00:02:18 is equal to ArcJet to which you can pass a key equal to get env.
00:02:25 And then you can say ArcJet API key.
00:02:29 And for now, I'll pass the rules array.
00:02:33 as an empty array because later on we can add additional rules to it.
00:02:37 We'll use this instance of Artjet to secure every part of our application from authentication to server actions.
00:02:45 So let's export it.
00:02:47 Export default AJ.
00:02:50 And then you can head over into our server actions by heading over to lib actions video.ts.
00:02:58 Then right here above our first server action and below our two helper functions, we'll create a reusable validator function.
00:03:07 And its goal will be to rate limit some of our server actions.
00:03:11 Because what malicious users most often do is just spam your application with specific calls.
00:03:17 So here, what we want to do is maybe not allow a user to upload more than let's say two videos a minute or something like that.
00:03:24 Because imagine if they spam your database with non-family-friendly content.
00:03:28 That wouldn't be good, would it?
00:03:30 So for that reason and many more, all enterprise applications have rate limiting implemented.
00:03:36 So let's define it simply by saying const validate with ArcJet and I'll make it equal to an asynchronous function that accepts something known as a fingerprint.
00:03:49 Not a fingerprinter, a fingerprint of a type string.
00:03:53 A fingerprint is something that allows us to connect who is the actor of that request, who is trying to make things happen,
00:04:00 and we'll connect it using the ID.
00:04:02 So I'll say const, rate limit is equal to aj, so now we're using that instance of ArcGit that we have created before, dot with rule.
00:04:14 And here you can provide what kind of rate limiting you want to have.
00:04:18 For rate limiting our server actions, I will use a fixed window limit.
00:04:23 So I can say fixed window, and you can provide some additional options to it, such as a mode of live, a time window of maybe something like four minutes,
00:04:35 or it can be one minute.
00:04:36 It can be whatever you want it to be.
00:04:38 max number of requests per time window.
00:04:41 So let's say that maybe we can make two requests per two minutes, or in this case, that will be one request per minute.
00:04:48 Since this platform is not about batch uploading tons of videos, but rather uploading one video or screen recording, I think one per minute should be more
00:04:57 than enough.
00:04:58 And we can also define the characteristics based off of which we'll do that rate limiting.
00:05:04 And we can say fingerprint right here.
00:05:07 Perfect.
00:05:08 Now, below, we can try to make our typical request by saying cons request is equal to await request coming from ArcGit.
00:05:19 And then here's where the magic happens.
00:05:21 We can say cons decision is equal to await rate limit, the one that we created above, dot protect.
00:05:31 And what are we protecting?
00:05:33 Well, the request that a user is trying to make.
00:05:36 And we can also connect the fingerprinting options right here at the end.
00:05:40 Finally, if a decision is that the request is denied for whatever reason, most likely because the rate limit has been exceeded,
00:05:51 we can throw a new error saying rate limit exceeded.
00:05:56 And now we can add this validator function wherever we want.
00:06:01 In this case, let's say that we want to add it to the save video detailed server action to secure the upload.
00:06:07 Here, we can take this user ID and pass it as a fingerprint so a single user can only make one request per minute, or I think we can maybe make it to two
00:06:16 per minute as one is a bit limiting.
00:06:18 Once we do that, right below getting the user ID, we can simply say, await, validate with ArcGit, which is the call to this function we created,
00:06:27 and then we pass in the user ID.
00:06:30 It is as simple as that.
00:06:32 So that is how you can add additional protections to any one of your server actions or database calls or functions that you're calling from within your application.
00:06:41 We'll test it out later on, but for now, I want to teach you how to protect any of our pages from bot attacks.
00:06:48 And to do that, we'll head over into the middleware.ts file.
00:06:52 because middleware gets called whenever we make any kind of request.
00:06:56 So right here below this middleware function, I will create a new function called validate and I'll make it equal to aj.withRule and we can call shield
00:07:09 right here coming from ArcGit and pass to it an object that says mode is set to live and what shield does is pretty crazy to be honest.
00:07:20 It protects your application against most common attacks, including the OWASP Top 10. This is a standard awareness document for developers and web application security.
00:07:31 And it includes the most common risks, such as different types of injections, cross-site scripting, and more.
00:07:38 And you can also chain additional rules to it by saying that would rule, For example, we can detect different bots.
00:07:46 You can import this from ArcGit again.
00:07:48 And pass in an option of mode live.
00:07:52 And you can also now decide which bots do you want to allow and which ones you want to disallow.
00:07:58 Because not every bot is malicious.
00:08:00 For example, you want to allow bots like a category of search engine, and there's also this Google crawler bot.
00:08:11 So you want to allow these bots while at the same time disallowing malicious ones.
00:08:17 And to turn this on, you can just say export default create middleware.
00:08:23 And we need to import this create middleware.
00:08:25 So I'll say import create middleware coming from at artjet forward slash next and pass the validate function we created just into it.
00:08:36 And that's it.
00:08:37 This will automatically turn the shield protection, which analyzes every request to your application to detect suspicious activity,
00:08:45 as well as the bot detection.
00:08:46 Now, I'll show you how we can test this later on, right within our application, so you see the outputs and decisions that AJ makes and which requests it
00:08:56 blocks and which it passes through.
00:08:58 But for now, I want to add it to just one more part of our application, and that is Auth.
00:09:04 So head over into App, API, Auth, All, Route.
00:09:10 Now within this file, we'll secure our app in two more ways.
00:09:14 The first one is through email validation.
00:09:18 What does that mean?
00:09:19 Well, if a user uses some kind of a spammy email or an email that has not been verified or a temporary email, we're not going to let them pass.
00:09:29 You know, there are a lot of these temporary email sites where you can just enter your email, copy it, and then create a free subscription maybe to your app.
00:09:37 But not anymore.
00:09:39 Now you're going to block them.
00:09:41 And the second one is rate limiting.
00:09:44 Yep.
00:09:44 Here as well, we'll implement rate limiting, but this time with a different algorithm.
00:09:49 Instead of just having a fixed window of time, we'll implement a sliding window.
00:09:54 I'll explain more as we get into it.
00:09:56 So let's actually create a new function, const email validation.
00:10:04 And I'll say that's equal to AJ.
00:10:07 dot with rule, and here we simply want to validate email, pass a mode of live, and then pass some additional options such as what we want to block.
00:10:21 In this case, it'll be disposable emails.
00:10:25 We also want to block invalid emails and finally emails with no MX records.
00:10:31 Alongside the email validation, we can also set the rate limits.
00:10:35 So I'll say const rate limit is equal to aj.withrule.
00:10:41 This time we'll implement a sliding window algorithm.
00:10:46 And what a sliding window does is it tracks the number of requests made by a client over a sliding window so that window moves with time.
00:10:55 This is useful to avoid stampede problems of the fixed window.
00:10:58 It's basically a bit more smoother rate limiting, preventing the user from making a burst of requests at the start of the window and then being blocked
00:11:06 for the rest of the window.
00:11:07 So we can also pass a mode of live, an interval of let's say two minutes, a max of two.
00:11:14 So in this case, we allow the user to log in two times in a two minute window, as well as characteristics.
00:11:21 We're going to do it using the fingerprint method, same as before.
00:11:25 And now that we have created those two new rules right below it, I will create a new const protected auth function, which is going to be an asynchronous
00:11:37 function that accepts a request of a type next request.
00:11:41 And it'll return a promise with an ArcJet decision.
00:11:46 Here, I can get access to the currently logged in user through a session.
00:11:50 So I'll say session is equal to await auth.api.getSession.
00:11:58 and we can pass the headers equal to rec.headers, so we know which user is currently logged in.
00:12:04 Then we can define an empty variable of a type string called userId, and then if a session?user?id exists, then we want to set the user ID to be equal
00:12:24 to session.user.id.
00:12:27 Else, we will simply set the user ID to be equal to the current IP address.
00:12:32 So I'll say IP and this is coming from ArcGit.
00:12:36 So I will import it right here at the top.
00:12:38 Import IP coming from at ArcGit forward slash IP.
00:12:45 And here you can pass the current request or by default set it to 127.001 which I believe is the default IP which ArcGit uses if no other IP is provided.
00:12:57 Then we can check if rec.nexturl.pathname.startswith forward slash API, forward slash auth, forward slash sign in.
00:13:11 That means that somebody's trying to, well, sign in, right?
00:13:14 So we can get access to the body of that request by awaiting the request dot clone dot Jason.
00:13:22 And then we can check if type of body dot email is equal to a string.
00:13:28 In that case, we can return email validation dot protect.
00:13:35 We pass in the request and we pass in the email coming from body.email.
00:13:41 So here we're turning on that email validation that we specified above.
00:13:45 And then outside of that if, we can also just return rate limit dot protect this request with the fingerprint, this time equal to the user ID that's trying
00:13:58 to log in.
00:13:59 So a single user will not be able to log in multiple times.
00:14:03 At least not in this sliding window.
00:14:06 Finally, right below this, we can say const auth-handlers is equal to to next.js handler.
00:14:14 And this one is coming from better auth.
00:14:17 So we don't need this one at the top if there was one.
00:14:19 And to it, we need to provide the auth.handler.
00:14:23 Below it, we have this get request.
00:14:25 And finally, we want to export a new post request from auth where we try to make a regular request of next request.
00:14:37 And here is where we'll actually call this protected auth, which basically acts as a middleware that accepts the request and then makes a decision.
00:14:46 So I'll say const decision is equal to await protected auth to which we pass the request.
00:14:55 Then if a decision is denied, in that case, it could be for a few reasons.
00:15:01 Maybe decision.reason.isEmail.
00:15:07 In that case, we can throw a new error and say email validation failed, else if maybe decision.reason.isRateLimit.
00:15:21 In that case, we can throw another new error saying something like rate limit exceeded.
00:15:30 And finally, else if, or just if in this case, maybe decision.reason.isShield is the case.
00:15:40 And in that case, we'll throw a new error saying something like shield turned on, protected against malicious actions.
00:15:52 Perfect.
00:15:52 And finally, below this if, we have to return odd handlers.
00:16:00 and then put this request right within it.
00:16:03 So with that in mind, we are now securing our authentication as well with email validation, raid limiting, and shielding against the most common malicious attacks.
00:16:14 So now that we've implemented ArcGit in a couple of places within our app, let's check it out in action.
00:16:20 The first thing we're doing here is making sure that temporary, dummy, or unverified emails cannot create accounts.
00:16:28 Right now, this doesn't help us a lot with this specific application as we have signed in with Google, but if you wanted to implement email and password authentication,
00:16:37 then that's going to be crucial to not have some dummy users coming in.
00:16:42 Next, there is rate limiting, and it'll prevent users from making repeated logging attempts.
00:16:48 Specifically, we've set the limit to two login attempts within two minutes.
00:16:51 So if you try to log in and out twice within that period, the third login attempt will be blocked, and you will get a rate limit exceeded error.
00:17:00 So let's see whether that happens.
00:17:02 I'll sign in for the first time.
00:17:03 There we go, we're in.
00:17:05 And I'll also log in for the second time.
00:17:08 And we're in.
00:17:10 And now third time's the charm.
00:17:12 If you click that button for the third time, you'll see that our application is throwing an error saying rate limit exceeded right here.
00:17:21 Of course, we would need to more graciously catch that in our application so we can display a little pop-up saying you've exceeded your login limit.
00:17:28 And this is once again to help prevent the bots.
00:17:31 Right on your dashboard, you'll be able to see that your application is protected and that there are three errors that happened.
00:17:37 Or rather, there were some decisions that ArcGit made to protect our application.
00:17:42 In this case, I clicked the button three times and I got rate limited.
00:17:46 So if you click right here, you can notice that we have exceeded the max reset time.
00:17:52 And if you just waited two more seconds, I would have been able to dive right into it.
00:17:56 And here, it's telling us based off of which rule we got denied.
00:18:00 So if you try it out one more time, you can see that now we're officially logged in.
00:18:05 But besides just rate limiting the logins, we have also rate limited the ability to upload more than two videos within a minute.
00:18:13 We don't necessarily have to go ahead and test this, but you can trust me that the output will be the same.
00:18:18 We're only allowing the users to upload what we believe is a normal amount of videos to our website.
00:18:24 And on top of the email validation and rate limiting, if you head back over to your project and head over to the middleware file,
00:18:32 you'll notice that we're also adding additional validation and security throughout the entirety of the application.
00:18:39 Why?
00:18:40 Well, because it's within the middleware and middleware runs before any other page is called.
00:18:46 In this case specifically, we're testing for the shield functionality, which as I mentioned, protects us from 10 most common malicious attacks.
00:18:55 And then we also added the detect capabilities.
00:18:59 Now, I'm not a hacker, so testing against these to actually get Arcjet to block this is super hard because we really have to act as malicious users or
00:19:08 act as bots.
00:19:09 So that's something that we can definitely consider testing for later on.
00:19:13 It could be a little lesson on how to try to break your application.
00:19:17 Oh, I couldn't wait until later.
00:19:19 I just wanted to test it out and check this out.
00:19:22 We're hitting errors left and right, which means that Arcjet is successfully blocking the bots.
00:19:27 Now, how was I able to achieve it and how we can test it on your end as well?
00:19:31 Well, let me show you.
00:19:33 If you head back over to your middleware.ts file, you'll notice that here we're checking and validating for bots.
00:19:41 But above, we had this middleware which was always redirecting to sign in.
00:19:48 And even if we try to test it on sign-in, that also wasn't working because this middleware isn't running at all on the sign-in page.
00:19:56 So the only way in which you can test it out right now is by commenting out the middleware, opening up our terminal.
00:20:03 So to test that, we can make a curl request.
00:20:06 curl-v localhost 3000. Now here, we're not acting as a malicious user, but we are a bot, because we're making this request from a terminal using curl and
00:20:20 not from the browser.
00:20:21 So we're definitely not a regular user wanting to use the app in the regular way.
00:20:26 So if I press enter, you'll notice that we get connection to host localhost left intact, code 403 forbidden.
00:20:35 So what this means, if you head over to ArcJet, you'll notice that it denied it for the reason that we are a curl bot, which means that the ArcJet implementation
00:20:47 is now successful.
00:20:48 And of course, this will be super useful for our public pages where we don't have the middleware, where it's redirecting us to sign in.
00:20:55 But for the time being, I'll bring us back to the middleware page that we had before.
00:21:00 If we decide to implement some additional pages, this will come in handy.
00:21:05 Great.