Protect your Next.js application's API with Guards
MakerKit uses API Guards allow to protect your Next.js API endpoints from unauthorized users, bad input, etc.
API Guards are similar to Page Guards, except they belong to the server and will protect our API endpoints.
As an example, let's take MakerKit's implementation for handling user invites.
We want to check that:
- the user is authenticated
- the endpoint method being called is correct
import { withAuthedUser } from '~/core/middleware/with-authed-user';export default function inviteHandler( req: NextApiRequest, res: NextApiResponse) { const handler = withPipe( withMethodsGuard(SUPPORTED_METHODS), withAuthedUser, inviteMembersToOrganizationHandler ); return withExceptionFilter(req, res)(handler);}
The withPipe
is a simple utility that can chain API handlers that respect the interface of a Next.js handler. The above handler can be written as follows, by passing in the parameters req
and res
explicitly:
export default withPipe( (req, res) => withMethodsGuard(SUPPORTED_METHODS)(req, res), (req, res) => withAuthedUser(req, res), (req, res) => inviteMembersToOrganizationHandler(req, res));
The final inviteMembersToOrganizationHandler
is the one that gets called at the end and is responsible for returning data to the client.
Makerkit Default API Guards
As you can see above, we're using various guards: withMethodsGuard
and withAuthedUser
.
These two guards will make sure that the request will get rejected if the user isn't authenticated or if the user submitted a request using a disallowed HTTP method.
You can also simplify the above if you only want to check if the user is signed-in:
export default function myAPIHandler( req: NextApiRequest, res: NextApiResponse) { await withAuthedUser(req, res); // do something with res}
withAuthedUser
The withAuthedUser
API guard will reject the API request when the user is not authenticated.
withMethodsGuard
The withMethodsGuard
API guard will reject the API request when the method is not among the ones used.
For example, the code below will never execute the handler myApiHandler
if the method is not GET
:
export default withPipe( withMethodsGuard(['GET']), myApiHandler);
withAdmin
The withAdmin
API guard will ensure the Firebase Admin is initialized before continuing with the rest of the handlers. This is useful before accessing any of the Firebase Admin packages.