In the previous section, we set up the NextAuth with a Github provider. In this section, we want to show you, how easy it it to authenticate your users using NextAuth package.
Please fork and clone the following repository:
https://github.com/WesternSydneyUniversity/comp3036-api-security
Make sure all the tests pass!
To authenticate a current user all you need to do is to import and call the following function (add it at the top of your src/app/api/tasks/route.ts
file):
import { auth } from "../../auth/[...nextauth]/options";
Then, you can modify your listTasks route handler as following:
import { NextResponse, type NextRequest } from "next/server";
import { auth } from "../../auth/[...nextauth]/options";
// In-memory data store for tasks
const tasks = [
{ userId: '1', id: 1, description: "Complete the project report", completed: false },
{ userId: '1', id: 2, description: "Clean the house", completed: true }
];
async function listTasks(req: NextRequest, res: NextResponse) {
// check if user is logged in
const session = await auth(); // <- That's it!
// only logged in users can view their tasks
if (session == null) {
return NextResponse.json({ message: "Unauthorized" }, { status: 401 });
}
return NextResponse.json(tasks.filter((task) => task.userId === session.user.id));
}
Please save the file and observe in terminal that tyour server was automatically reloaded.
Time to solve zod
. Make sure you validate your schema in a try/catch block and return errors when occurred:
try {
// Validate incoming data
const body = await req.json();
const validatedData = postSchema.parse(body);
// ...
} catch (error) {
if (error instanceof z.ZodError) {
return NextResponse.json(
{ error: "Invalid Data", errors: error.errors },
{ status: 400 }
);
}
return NextResponse.json({ error: "Server error" }, { status: 500 });
}
Please run the following command:
curl http://localhost:3000/api/tasks
You should now recieve the following error:
{"message":"Unauthorized"}
Now, open your project in the browser, navigating to http://localhost:3000
and sign in using your github credentials. Try the following command again:
curl http://localhost:3000/api/tasks
OH OH! Still unauthorised! What's going on!
Well, the problem is, that when you login, your login cookie is issued and stored in your browser. Your terminal does not have access to this cookie. So, how can we solve it?
Just like your terminal, you can run commands in your browser developer console. The commands are “javascript” and not “bash” command. Please open your developer console by pressing “CMD+SHIFT+I” on Mac or “ALT+SHIFT+I” on Windows. Then, open your “console” by click on the “console” tab. In the console type the following command and press enter:
await (await fetch("/api/tasks")).json()
The result should look like the following:
It's not very exciting, but we are now using the user's credentials to receive only the user's tasks!
We know that the browser has the information about the logged-in user. This information is stored in the browser “Cookie”. We need to extract and reuse that cookie. Please re-open your browser console, and this time, open the “Application” tab. On the left, under the “Storage” section, expand the “Cookies” section and then click on “http://localhost:3000”. You should see the following:
There might be some more cookies, but we are after the “next-auth.session-token,” so please copy its entire value. My value of the session token is the following:
176e99d3-2fe2-4464-a047-4fdeb3dfe276
We are now ready to send authorised requests to our API backend by including the value of this cookie in the curl request. Please run the following command, replacing the value of the cookie with your session token from above.
curl http://localhost:3000/api/tasks --cookie "next-auth.session-token=YOUR_SESSION_TOKEN"
💰 PROFIT! You are now able to send authorised requests
Please complete the rest of the handlers to use authentication