Part 131: Enhancing Application Security: Restricting Access to Authenticated Users
[App] Authentication User Database

In our journey of building a secure and user-friendly application, we've successfully implemented password encryption to protect user credentials. With this foundation in place, our authentication system is robust, allowing users to sign up, sign in, and sign out securely. However, our next step is crucial: restricting certain parts of our application to authenticated users only. Specifically, we want to ensure that only logged-in users can post comments on reviews. This article will guide you through implementing these restrictions.
Why Restrict Access?
Restricting access to certain features or areas of an application is a common practice to ensure that only verified users can perform specific actions. It not only enhances security but also personalizes the user experience by leveraging user data, such as names, to make interactions more seamless.
Steps to Restrict Access
1. Determine User Authentication Status
To restrict access, we first need to determine if a user is authenticated. In our application, we have a getUserFromSession function that retrieves user information from the session. We'll use this function to check if a user is logged in when they visit the ReviewPage.
// File path: app/reviews/[slug]/page.jsx
import { getUserFromSession } from '@/lib/auth';
export default async function ReviewPage({ params: { slug } }) {
const user = await getUserFromSession();
// ...
}2. Conditional Rendering of Comment Form
Once we have the user's authentication status, we can conditionally render the comment form. If the user is authenticated, they will see the form. If not, we'll display a message encouraging them to sign in.
// File path: app/reviews/[slug]/page.jsx
import Link from 'next/link';
export default async function ReviewPage({ params: { slug } }) {
console.log('[ReviewPage] rendering', slug);
const review = await getReview(slug);
if (!review) {
notFound();
}
const user = await getUserFromSession();
return (
<>
<Heading>{review.title}</Heading>
<p className="font-semibold pb-3">
{review.subtitle}
</p>
<div className="flex gap-3 items-baseline">
<p className="italic pb-2">{review.date}</p>
<ShareLinkButton />
</div>
<Image src={review.image} alt="" priority
width="640" height="360" className="mb-2 rounded"
/>
<article dangerouslySetInnerHTML={{ __html: review.body }}
className="max-w-screen-sm prose prose-slate"
/>
<section className="border-dashed border-t max-w-screen-sm mt-3 py-3">
<h2 className="font-bold flex gap-2 items-center text-xl">
<ChatBubbleBottomCenterTextIcon className="h-6 w-6" />
Comments
</h2>
{user ? (
<CommentForm slug={slug} title={review.title} userName={user.name} />
) : (
<div className="border bg-white mt-3 px-3 py-3 rounded">
<Link href="/sign-in" className="text-orange-800 hover:underline">
Sign in
</Link> to have your say!
</div>
)}
<Suspense fallback={<CommentListSkeleton />}>
<CommentList slug={slug} />
</Suspense>
</section>
</>
);
}3. Pre-Populate User Name in the Comment Form
Since users must be signed in to comment, we already have their names. Instead of asking users to enter their names again, we'll display the name we have on record.
// File path: components/CommentForm.jsx
export default function CommentForm({ slug, title, userName }) {
const [state, handleSubmit] = useFormState(createCommentAction);
return (
<form onSubmit={handleSubmit}
className="border bg-white flex flex-col gap-2 mt-3 px-3 py-3 rounded">
<p className="pb-1">
Already played <strong>{title}</strong>? Have your say!
</p>
<input type="hidden" name="slug" value={slug} />
<div className="flex">
<label className="shrink-0 w-32">
Your name
</label>
<span>{userName}</span>
</div>
<div className="flex">
<label htmlFor="messageField" className="shrink-0 w-32">
Your comment
</label>
<textarea id="messageField" name="message"
className="border px-2 py-1 rounded w-full"
/>
</div>
{Boolean(state.error) && (
<p className="text-red-700">{state.error.message}</p>
)}
<button type="submit" disabled={state.loading}
className="bg-orange-800 rounded px-2 py-1 self-center
text-slate-50 w-32 hover:bg-orange-700
disabled:bg-slate-500 disabled:cursor-not-allowed">
Submit
</button>
</form>
);
}4. Update Comment Action
Although we haven't touched the server-side logic for creating comments yet, remember that the server action will need to fetch user data from the session, not from form inputs, as we no longer collect the user's name through the form.
Conclusion
By restricting access to certain features based on user authentication status, we're enhancing both the security and user experience of our application. Users are encouraged to sign in to participate, and once authenticated, they enjoy a more personalized interaction with the app. This is a crucial step in building a secure, user-friendly application. As always, ensure your server-side logic is updated to reflect these changes, especially when handling user data.
Last updated