I've created an app successfully using the nextjs learn (the app router way) - specifically the "Adding Authentication" part.
Authentication works fine.
Now, I wanted to add an api
route.
So I've created a file route.ts
under app/api/my-api/
with the content:
import { NextResponse } from "next/server";
export async function POST(req: Request) {
return NextResponse.json({ message: "hello" }, { status: 200 });
}
I removed the api
part from the matcher of middleware.ts
's export const config
. Meaning, authentication should apply to /api/...
as well:
import NextAuth from 'next-auth';
import { authConfig } from './auth.config';
export default NextAuth(authConfig).auth;
export const config = {
matcher: ['/((?!_next/static|_next/image|.*\\.png$).*)'],
};
I would expect the following command to fail due to no authentication, but it passes:
curl -v -X POST 'http://localhost:3000/api/my-api'
...
< HTTP/1.1 200 OK
As in the example,
auth.ts
is
import NextAuth from 'next-auth';
import Credentials from 'next-auth/providers/credentials';
import { authConfig } from './auth.config';
import { sql } from '@vercel/postgres';
import { z } from 'zod';
import type { User } from '@/app/lib/definitions';
import bcrypt from 'bcrypt';
// ...
export const { auth, signIn, signOut } = NextAuth({
...authConfig,
providers: [
Credentials({
async authorize(credentials) {
// ...
if (parsedCredentials.success) {
const { email, password } = parsedCredentials.data;
const user = await getUser(email);
if (!user) return null;
const passwordsMatch = await bcrypt.compare(password, user.password);
if (passwordsMatch) return user;
}
console.log('Invalid credentials');
return null;
},
}),
],
});
And auth.config.ts
is:
import type { NextAuthConfig } from 'next-auth';
export const authConfig = {
pages: {
signIn: '/login',
},
callbacks: {
authorized({ auth, request: { nextUrl } }) {
const isLoggedIn = !!auth?.user;
const isOnDashboard = nextUrl.pathname.startsWith('/dashboard');
if (isOnDashboard) {
if (isLoggedIn) return true;
return false; // Redirect unauthenticated users to login page
} else if (isLoggedIn) {
return Response.redirect(new URL('/dashboard', nextUrl));
}
return true;
},
},
providers: [], // Add providers with an empty array for now
} satisfies NextAuthConfig;
So, looks like there are 2 different things here:
next-auth
which is used in that tutorial https://authjs.dev/reference/nextjsnextjs
middlewareAparently they cannot be mixed.
I had to do there things for making authentication using next-auth
to work for api
in addition to the tutorial:
auth.config.ts
, the last return true
should be return false
, so api
calls will not be authenticated.auth.config.ts
, change the function signature to authorized({ request, auth })
, so I can use what's in request
. I somehow learned it from hereauth.config.ts
's authorized()
my own logic. For example:if (request.nextUrl.pathname.startsWith('/api')) {
...
}