Build a Fullstack Next.js App, v4

Creating Protected Server Actions

Brian Holt
Databricks
Build a Fullstack Next.js App, v4

Lesson Description

The "Creating Protected Server Actions" Lesson is part of the full, Build a Fullstack Next.js App, v4 course featured in this preview video. Here's what you'd learn in this lesson:

Brian walks through creating server actions in React and discusses the importance of protecting server actions to prevent unauthorized access. He also walks through creating server actions for updating and deleting articles.

Preview

Transcript from the "Creating Protected Server Actions" Lesson

[00:00:00]
>> Brian Holt: So we have two files in here, which will end up being the author, and I guess I did not put them in the complete UI. So we're going to go grab this action here, which is here. We're going to create a folder called actions and one of them is going to be called articles. And let's just actually, you know what, we'll just go code it by hand here, because I think that's going to be the most demonstrative of how we do this, and this is really important.

[00:00:44]
So app actions, articles. So we're going to do a React server action, right? So whenever someone submits an article on the page, it's going to be reserved via, received via a server action. So we get to use the very fun use server directive, which is not controversial of using directives at all. If that joke's not landing with you, it's very controversial right now because they announced use cache with React 16.

[00:01:15]
And everyone's like, why is everything a directive, and now they're fighting with each other on Twitter. It's all very funny. I get both sides, right? Like on one hand, it is annoying that everything is a directive. On the other hand, like, is imported code from a library so much different? Yes, no, I mean, am I thrilled that there's another directive?

[00:01:44]
No, I think that's probably the most I'll say about that. So, okay, we're going to import stack server app up here as well, from stack/server. And yeah, let's do this export async function create article. And it's going to receive data, we'll call this like a create article input, and we'll create this type here in just a second.

[00:02:28]
Okay, and we'll do that first. So I'm just going to say here first, console.log, and I put an emoji here, so sparkles. I love sparkles. Create article called with data. And return success true, message article created. We don't have a database yet, so it's not actually going anywhere, so we'll implement that here in just a second.

[00:03:09]
But like, assuming this was saving to the database, what's the problem with the server action? If you know the URL, anybody can call this. Like, despite the fact that it's a React server component, React server action happening here, there's still data coming from the frontend to the backend. How do you think it gets there?

[00:03:32]
It's an API endpoint, right? It's an RPC is really what it is, right? Which is a, what is it, remote protocol, I never know what the C stands for, something. Someone's going to tell me in chat right away, like it's this Brian, obviously. If you're watching the data in like the network panel, you can find out what the API endpoint it is and like how it's invoking that function, like that's not a secret.

[00:04:00]
It's not even tried to be hidden from somebody. So all this to say is you do still have to protect your server actions, or else someone can invoke it with like untrusted data. So all that to say is you have to do something like this, const user equals, this should be async, yep, stack server app dot get user. And yeah, we need to await this await.

[00:04:52]
And then say if there is no user, then throw new error unauthorized. Okay, so you'll end up doing this a bunch in server actions, just because like you do still need to protect these as if they were normal API endpoints, because they are, right? It's kind of like hiding the complexity of creating APIs for you. That's the magic of server actions, if you like that or not.

[00:05:16]
But you need to treat them still with the same level of security. Okay, and then here you'd have to make the interface here, which should just be the export type create article input. It's going to have a title, which is a string. Content, which is a string. Author ID, which is a string. And image URL which may or may not come, so I'll put the question mark, it's also a string.

[00:06:01]
Okay, we now have a typed create article input. And then should we call the rest of? There's not really a lot left here to do, so yeah, let's just do it. We're going to have, this is going to look really similar when you do update, so update article input. But a couple of things here. Oh, sorry, this needs an equal sign as well.

[00:06:29]
All these are going to be optional. And there's no author ID. Why? Because the author ID should be pulled off the user and should not be coming from the frontend, you shouldn't trust the frontend with that. Okay, so that's create article. Let's go to. I mean this is going to be essential, this is going to be for now, it's going to be the exact same.

[00:07:17]
Except it's going to be update article. This is going to be an update article input. And we'll say this is update called. Give us a new emoji if you want to. What I do like right? Something like that. I don't know about you. Some people like get really bothered that I put emojis in here, but it helps me parse the logs at a glance, which is why I put them in there.

[00:07:46]
Okay, for now that's going to be enough. I mean, what you're going to do down here is const author ID is going to be equal to user dot, I think it's just ID, right, and then now I can use the author ID down here. Do author ID like this. And then delete is much the same. Again, you can even go as far as basically just copying and pasting this again.

[00:08:31]
Function delete article. We're basically just putting these like stubs. This will just be taking an ID, right? Because you're just going to be deleting that. So it's going to be a string. And we'll call this delete the and changes to be like a trash bin. So again, for both update and delete, we'll do this momentarily, but you would get here and you'd be like, is this person authorized to edit this?

[00:09:07]
Is this person authorized to delete this, right? Just because you're logged in doesn't mean you can delete any article on the wiki. Okay, so this is good for articles for now. Let's just go plug them into the wiki, so on the edit pages. So on the ID here page. That's actually going to be in the component, not on the page itself.

[00:09:42]
So in the component, the wiki editor. We're going to import, and we want the create article from app articles. Well, I think that's good now, at least cause you see how to protect actions, we'll get later here in just a second of actually saving these to the database, and then we would just go plug these into our forms.

[00:10:07]
I think what we'll do instead is we'll go finish setting up all the protected routes and stuff like that, and then we'll just kind of pull the data or pull the code from the next step here. But you can see here with the upload.ts, this looks relatively the same, this is just uploading an image here. And it's the exact same thing here.

[00:10:43]
You just say, can this user upload this image? If not, then redirect them. Otherwise, this is a pretty, you can use Cloudinary or something like here, we'll use Vercel blob storage actually. Okay. But that's it, that's again, the nice thing about using Stack is you're able to just protect a route this way. So we're going to go ahead and go grab 03 auth, just so that we don't have to do all the wiring up from all these forms together, for both the create and the edit and the delete.

Learn Straight from the Experts Who Shape the Modern Web

  • 250+
    In-depth Courses
  • Industry Leading Experts
  • 24
    Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now