When building your XM Cloud front end, you might need to create a component that requires a GraphQL call to get the necessary data (such as building a custom breadcrumb). Your initial thought might be to create a simple GraphQL fetch inside your .tsx
component; however, this is the last thing you should do.
Making client-side calls is a significant security risk. In the past, this was mitigated by Sitecore using a C# backend. If you're migrating from a C# solution, you might not realize that Next.js runs all its code directly on the client.
When your API call is made from the client-side, any sensitive information like API keys, access tokens, or credentials used in the request can be exposed. This data becomes visible in the network traffic and accessible through the browser's developer tools.
Not only is the sensitive information visible on the client-side, attackers could modify the request parameters, headers, or even payload to perform unauthorized actions. Imagine someone trying to access restricted data or attempting to exploit API vulnerabilities.
XSS attacks are a big deal, and something you need to do your best to avoid. Now granted, this isn't an issue directly related to the client-side API calls, but if an attacker can inject malicious scripts into your client-side code, you're also giving them the opportunity to manipulate API requests or responses.
Next.js has a feature that allows you to make your API calls from the server. API Routes allow you to essentially build a public API that you can call on your client side. If you navigate to the pages
folder inside your Sitecore solution, you should find and api
folder.
All .ts
or .js
files inside the api
folder will be treated as an endpoint for your public API and will run on the server side. The endpoints url will be /api/[slug]
.
To create an endpoint, you just need to import NextApiRequest
and NextApiResponse
, then assign them to the request and response items.
export default function handler(
req: NextApiRequest,
res: NextApiResponse
) {
... //Add your GraphQL or Private API call here
return res.status(response.status).send(data); //Return the data to the client
}
Here is some example code that you can use as reference to build out your first API endpoint:
import { NextApiRequest, NextApiResponse } from 'next';
import fetch from 'node-fetch';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { token } = req.body;
if (!token) {
return res.status(400).send({ message: 'Missing Bearer token in request body' });
}
try {
const headers = new Headers({
Authorization: `Bearer ${token}`,
Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json',
});
//Add your sitecore GraphQL call here or do a Fetch to your private API
const response = await fetch('www.example.com/api/test', {
method: 'GET',
headers: Object.fromEntries(headers),
});
const data = await response.json();
return res.status(response.status).send(data);
} catch (error: unknown) {
return res.status(400).send({ message: 'Invalid request: ' + message });
}
}
While the ease and directness of client-side GraphQL calls in Sitecore projects might seem appealing, the security risks they pose cannot be ignored. The potential for exposing sensitive data, allowing request manipulation, and opening doors to XSS attacks make this approach unsuitable for secure web development. Instead, leveraging Next.js's API Routes to handle GraphQL or other API requests server-side provides a safer, more secure way to manage data interactions. By abstracting API logic to the server, you not only protect your application from common security threats but also ensure a cleaner, more maintainable codebase. Implementing these server-side functions is a straightforward process that significantly enhances the security and functionality of your Sitecore XM Cloud front end.