Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Elaborate on credentialed fetch behaviour #10421

Merged
merged 7 commits into from
Jul 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/orange-roses-destroy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

docs: Elaborate on credentialed `fetch` behaviour
25 changes: 18 additions & 7 deletions documentation/docs/20-core-concepts/20-load.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,10 +231,11 @@ Given a `route.id` of `/a/[b]/[...c]` and a `url.pathname` of `/a/x/y/z`, the `p

To get data from an external API or a `+server.js` handler, you can use the provided `fetch` function, which behaves identically to the [native `fetch` web API](https://developer.mozilla.org/en-US/docs/Web/API/fetch) with a few additional features:

- it can be used to make credentialed requests on the server, as it inherits the `cookie` and `authorization` headers for the page request
- it can make relative requests on the server (ordinarily, `fetch` requires a URL with an origin when used in a server context)
- internal requests (e.g. for `+server.js` routes) go direct to the handler function when running on the server, without the overhead of an HTTP call
- during server-side rendering, the response will be captured and inlined into the rendered HTML by hooking into the `text` and `json` methods of the `Response` object. Note that headers will _not_ be serialized, unless explicitly included via [`filterSerializedResponseHeaders`](hooks#server-hooks-handle). Then, during hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request - if you got a warning in your browser console when using the browser `fetch` instead of the `load` `fetch`, this is why.
- It can be used to make credentialed requests on the server, as it inherits the `cookie` and `authorization` headers for the page request.
- It can make relative requests on the server (ordinarily, `fetch` requires a URL with an origin when used in a server context).
- Internal requests (e.g. for `+server.js` routes) go directly to the handler function when running on the server, without the overhead of an HTTP call.
- During server-side rendering, the response will be captured and inlined into the rendered HTML by hooking into the `text` and `json` methods of the `Response` object. Note that headers will _not_ be serialized, unless explicitly included via [`filterSerializedResponseHeaders`](hooks#server-hooks-handle).
- During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request - if you received a warning in your browser console when using the browser `fetch` instead of the `load` `fetch`, this is why.

```js
/// file: src/routes/items/[id]/+page.js
Expand All @@ -247,9 +248,7 @@ export async function load({ fetch, params }) {
}
```

> Cookies will only be passed through if the target host is the same as the SvelteKit application or a more specific subdomain of it.

## Cookies and headers
## Cookies

A server `load` function can get and set [`cookies`](types#public-types-cookies).

Expand All @@ -274,8 +273,20 @@ export async function load({ cookies }) {
}
```

Cookies will only be passed through the provided `fetch` function if the target host is the same as the SvelteKit application or a more specific subdomain of it.

For example, if SvelteKit is serving my.domain.com:
- domain.com WILL NOT receive cookies
- my.domain.com WILL receive cookies
- api.domain.dom WILL NOT receive cookies
- sub.my.domain.com WILL receive cookies

Other cookies will not be passed when `credentials: 'include'` is set, because SvelteKit does not know which domain which cookie belongs to (the browser does not pass this information along), so it's not safe to forward any of them. Use the [handleFetch hook](hooks#server-hooks-handlefetch) to work around it.

> When setting cookies, be aware of the `path` property. By default, the `path` of a cookie is the current pathname. If you for example set a cookie at page `admin/user`, the cookie will only be available within the `admin` pages by default. In most cases you likely want to set `path` to `'/'` to make the cookie available throughout your app.

## Headers

Both server and universal `load` functions have access to a `setHeaders` function that, when running on the server, can set headers for the response. (When running in the browser, `setHeaders` has no effect.) This is useful if you want the page to be cached, for example:

```js
Expand Down
2 changes: 1 addition & 1 deletion documentation/docs/20-core-concepts/50-state-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const actions = {

The `user` variable is shared by everyone who connects to this server. If Alice submitted an embarrassing secret, and Bob visited the page after her, Bob would know Alice's secret. In addition, when Alice returns to the site later in the day, the server may have restarted, losing her data.

Instead, you should _authenticate_ the user using [`cookies`](load#cookies-and-headers) and persist the data to a database.
Instead, you should _authenticate_ the user using [`cookies`](load#cookies) and persist the data to a database.

## No side-effects in load

Expand Down
22 changes: 12 additions & 10 deletions packages/kit/src/exports/public.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -697,13 +697,13 @@ export interface LoadEvent<
/**
* `fetch` is equivalent to the [native `fetch` web API](https://developer.mozilla.org/en-US/docs/Web/API/fetch), with a few additional features:
*
* - it can be used to make credentialed requests on the server, as it inherits the `cookie` and `authorization` headers for the page request
* - it can make relative requests on the server (ordinarily, `fetch` requires a URL with an origin when used in a server context)
* - internal requests (e.g. for `+server.js` routes) go directly to the handler function when running on the server, without the overhead of an HTTP call
* - during server-side rendering, the response will be captured and inlined into the rendered HTML. Note that headers will _not_ be serialized, unless explicitly included via [`filterSerializedResponseHeaders`](https://kit.svelte.dev/docs/hooks#server-hooks-handle)
* - during hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request
* - It can be used to make credentialed requests on the server, as it inherits the `cookie` and `authorization` headers for the page request.
* - It can make relative requests on the server (ordinarily, `fetch` requires a URL with an origin when used in a server context).
* - Internal requests (e.g. for `+server.js` routes) go directly to the handler function when running on the server, without the overhead of an HTTP call.
* - During server-side rendering, the response will be captured and inlined into the rendered HTML by hooking into the `text` and `json` methods of the `Response` object. Note that headers will _not_ be serialized, unless explicitly included via [`filterSerializedResponseHeaders`](https://kit.svelte.dev/docs/hooks#server-hooks-handle)
* - During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request.
*
* > Cookies will only be passed through if the target host is the same as the SvelteKit application or a more specific subdomain of it.
* You can learn more about making credentialed requests with cookies [here](https://kit.svelte.dev/docs/load#cookies)
*/
fetch: typeof fetch;
/**
Expand Down Expand Up @@ -949,11 +949,13 @@ export interface RequestEvent<
/**
* `fetch` is equivalent to the [native `fetch` web API](https://developer.mozilla.org/en-US/docs/Web/API/fetch), with a few additional features:
*
* - it can be used to make credentialed requests on the server, as it inherits the `cookie` and `authorization` headers for the page request
* - it can make relative requests on the server (ordinarily, `fetch` requires a URL with an origin when used in a server context)
* - internal requests (e.g. for `+server.js` routes) go directly to the handler function when running on the server, without the overhead of an HTTP call
* - It can be used to make credentialed requests on the server, as it inherits the `cookie` and `authorization` headers for the page request.
* - It can make relative requests on the server (ordinarily, `fetch` requires a URL with an origin when used in a server context).
* - Internal requests (e.g. for `+server.js` routes) go directly to the handler function when running on the server, without the overhead of an HTTP call.
* - During server-side rendering, the response will be captured and inlined into the rendered HTML by hooking into the `text` and `json` methods of the `Response` object. Note that headers will _not_ be serialized, unless explicitly included via [`filterSerializedResponseHeaders`](https://kit.svelte.dev/docs/hooks#server-hooks-handle)
* - During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request.
*
* > Cookies will only be passed through if the target host is the same as the SvelteKit application or a more specific subdomain of it.
* You can learn more about making credentialed requests with cookies [here](https://kit.svelte.dev/docs/load#cookies)
*/
fetch: typeof fetch;
/**
Expand Down
4 changes: 3 additions & 1 deletion packages/kit/src/runtime/server/fetch.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,16 @@ export function create_fetch({ event, options, manifest, state, get_cookie_heade
}

if (url.origin !== event.url.origin) {
// allow cookie passthrough for "same-origin"
// Allow cookie passthrough for "credentials: same-origin" and "credentials: include"
// if SvelteKit is serving my.domain.com:
// - domain.com WILL NOT receive cookies
// - my.domain.com WILL receive cookies
// - api.domain.dom WILL NOT receive cookies
// - sub.my.domain.com WILL receive cookies
// ports do not affect the resolution
// leading dot prevents mydomain.com matching domain.com
// Do not forward other cookies for "credentials: include" because we don't know
// which cookie belongs to which domain (browser does not pass this info)
if (`.${url.hostname}`.endsWith(`.${event.url.hostname}`) && credentials !== 'omit') {
const cookie = get_cookie_header(url, request.headers.get('cookie'));
if (cookie) request.headers.set('cookie', cookie);
Expand Down