diff --git a/docs/menu.cue b/docs/menu.cue index c57de9ed1a..60fed75564 100644 --- a/docs/menu.cue +++ b/docs/menu.cue @@ -724,6 +724,11 @@ text: "Static Assets" path: "/ts/primitives/static-assets" file: "ts/primitives/static-assets" + }, { + kind: "basic" + text: "Cookies" + path: "/ts/primitives/cookies" + file: "ts/primitives/cookies" }] }, { kind: "basic" diff --git a/docs/ts/primitives/cookies.mdx b/docs/ts/primitives/cookies.mdx new file mode 100644 index 0000000000..4cdeb27f90 --- /dev/null +++ b/docs/ts/primitives/cookies.mdx @@ -0,0 +1,187 @@ +--- +seotitle: Using Cookies in Encore.ts API Endpoints +seodesc: Learn how to work with cookies in your TypeScript backend applications built with Encore.ts +title: Working with Cookies +subtitle: Type-safe cookie handling for web applications +lang: ts +--- + +Encore.ts provides type-safe cookie handling for your API endpoints. Cookies are commonly used for session management, personalization, and tracking. This guide explains how to use cookies in different contexts within your Encore.ts application. + +## Where Cookies Can Be Used + +Cookies can be utilized in three main contexts within Encore.ts: + +1. **Auth handler parameters**: Access cookies during authentication +2. **Response cookies**: Set cookies to be sent back to clients +3. **Request cookies**: Access cookies sent by clients + +## Using Cookies in Auth Handlers + +Cookies can be used in authentication handlers: + +```ts +import { Cookie, Gateway } from "encore.dev/api"; +import { authHandler } from "encore.dev/auth"; + +// Define auth parameters with cookies +interface AuthParams { + sessionId: Cookie<"sessionId">; +} + +// Auth handler that uses cookies +const auth = authHandler(async ({ sessionId }) => { + return validateAndGetUser(sessionId.value); +}); + +// Configure the gateway with the auth handler +export const gateway = new Gateway({ + authHandler: auth, +}); +``` + +## Setting Cookies in Responses + +You can set cookies in your API responses by including them in your response type: + +```ts +import { api, Cookie } from "encore.dev/api"; + +// Define a response type with a cookie +interface LoginResponse { + user: UserData; + sessionId: Cookie<"sessionId">; +} + +// Create an API endpoint that sets a cookie +export const login = api({ + method: "POST", + path: "/login", + expose: true, +}, async (params): Promise => { + // Authenticate user + const user = await authenticateUser(params.username, params.password); + const sessionId = generateSessionId(); + + // Store session + await storeSession(sessionId, user.id); + + // Return response with cookie + return { + user, + sessionId: { + value: sessionId, + httpOnly: true, + secure: true, + sameSite: "Strict", + maxAge: 60 * 60 * 24 * 7, // 7 days + } + }; +}); +``` + +## Using Cookies in Requests + +When creating API endpoints, you can access cookies sent by the client by defining them in your parameter type: + +```ts +import { api } from "encore.dev/api"; + +// Define a request type with a cookie +interface Params { + language?: Cookie<"language">; +} + +// Create an API endpoint that uses the cookie +export const get = api( + { + method: "GET", + path: "/user/profile", + expose: true, + }, + async ({ language }) => { + // Access the cookie value + const lang = language?.value ?? "en"; + return { msg: `your language: ${lang}` }; + }, +);``` + +## Typed Cookie Values + +Encore.ts allows you to specify the type of cookie values for improved type safety. By default, cookie values are strings, but you can define cookies with different data types. If you omit the type parameter, Encore.ts will automatically use `string` as the type. + +### Available Cookie Types + +You can use the following types for cookie values: + +- `string`: Text data (default when generic parameter is omitted) +- `number`: Numeric values +- `boolean`: True/false values +- `Date`: Date objects + +### How to Specify Cookie Types + +When defining cookies, you can specify the type using the generic parameter: + +```ts +interface UserPreferences { + // Cookies with different types + userId: Cookie; + darkMode: Cookie; + lastVisit: Cookie; + language: Cookie; + // Using omitted type parameter (implicitly string) + theme: Cookie<"theme">; +} + +export const savePreferences = api({ + method: "POST", + path: "/user/preferences", + expose: true, +}, async (params) => { + // Type-safe access to cookie values + const userId = params.userId.value; // number + const isDarkMode = params.darkMode.value; // boolean + const lastVisit = params.lastVisit.value; // Date + const language = params.language.value; // string + const theme = params.theme.value; // string (implicitly typed) + + // Save preferences... +}); +``` + +## Cookie Options + +When setting cookies, you can configure various options: + +- **expires**: Sets an expiration date +- **maxAge**: Sets the cookie lifetime in seconds +- **domain**: Specifies which domains can receive the cookie +- **path**: Limits the cookie to a specific path +- **secure**: Only sends the cookie over HTTPS +- **httpOnly**: Makes the cookie inaccessible to JavaScript +- **sameSite**: Controls when cookies are sent with cross-site requests + - `"Strict"`: Only sent in same-site requests + - `"Lax"`: Sent with same-site requests and top-level navigations + - `"None"`: Sent with all requests (requires `secure: true`) +- **partitioned**: Creates a partitioned cookie using the CHIPS model + +## Generated client + +The generated Encore.ts client does not explicitly handle cookies. Instead, it relies on the browser's built-in cookie handling. When using the client in browser environments, cookies will be automatically included in requests and stored from responses. + +For cross-site requests, you need to configure the client to include credentials: + +```ts +// Create a client that includes credentials (cookies) for cross-site requests +const client = new Client(Local, { requestInit: { credentials: "include" } }); +``` + +## Best Practices + +1. Use `httpOnly: true` for cookies containing sensitive data +2. Set `secure: true` for production environments +3. Configure appropriate `sameSite` settings based on your requirements +4. Use the `maxAge` or `expires` options to limit cookie lifetime + +By following these guidelines, you can effectively leverage cookies in your Encore.ts applications while maintaining security and type safety. diff --git a/docs/ts/primitives/defining-apis.mdx b/docs/ts/primitives/defining-apis.mdx index fd2b992eae..d9bf9967ad 100644 --- a/docs/ts/primitives/defining-apis.mdx +++ b/docs/ts/primitives/defining-apis.mdx @@ -179,6 +179,22 @@ export const getBlogPost = api( ) ``` +### Cookie parameters + +Cookies are defined by setting the field type to `Cookie<"Name-Of-Cookie">`. It can be used in both request and response data types. + +In the example below we define an optional field that will be parsed from the cookie header. + +```ts +import { Cookie } from "encore.dev/api"; + +interface Params { + settings?: Cookie<"settings">; // parsed from cookie header +} +``` + +Read more about cookies [here](/docs/ts/primitives/cookies) + ### Fallback routes Encore supports defining fallback routes that will be called if no other endpoint matches the request,