Out of the box, SvelteKit does not set any CORS headers on its API routes (+server.js/ts
), so if you have your regular non-Svelte site on the domain example.com
and a SvelteKit instance on svelte.example.com
then your site on example.com
won’t be able to make fetch/AJAX requests to SvelteKit.
To fix this, let’s see how we can allow requests from any site:
First, create the file hooks.server.ts
See documentation
Add the following code. Note: This will add Access-Control-Allow-Origin: *
to all requests under /api
. So your API routes need to be under src/routes/api/...
import type { Handle } from '@sveltejs/kit';
export const handle: Handle = async ({ resolve, event }) => {
// Apply CORS header for API routes
if (event.url.pathname.startsWith('/api')) {
// Required for CORS to work
if(event.request.method === 'OPTIONS') {
return new Response(null, {
headers: {
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': '*',
}
});
}
}
const response = await resolve(event);
if (event.url.pathname.startsWith('/api')) {
response.headers.append('Access-Control-Allow-Origin', `*`);
}
return response;
};
This will allow CORS from any website, so you might want to tighten up these rules in production. For example if you want to allow only *.example.com
to access CORS you can adapt the above code like this. This will send back Access-Control-Allow-Origin: yourhostname.example.com
instead of *
.
// Inside handle()
const validDomains = /^(.*)?\.?example\.com$/;
let cors = false;
let originDomain = null;
try {
originDomain = new URL(event.request.headers.get('origin') || '').hostname;
if(validDomains.test(originDomain)) {
cors = `https://${originDomain}`
}
} catch (e) {
console.log('Invalid origin', e);
}
//...
if(event.request.method === 'OPTIONS' && cors) {
return new Response(null, {
headers: {
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
'Access-Control-Allow-Origin': cors,
'Access-Control-Allow-Headers': '*'
}
});
}
//...
response.headers.append('Access-Control-Allow-Origin', cors);