Working with Cookies

Type-safe cookie handling for web applications

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:

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<AuthParams, User>(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:

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<LoginParams, LoginResponse>({ method: "POST", path: "/login", expose: true, }, async (params): Promise<LoginResponse> => { // 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:

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<Params, { msg: string }>( { method: "GET", path: "/user/profile", expose: true, }, async ({ language }) => { // Access the cookie value const lang = language?.value ?? "en"; return { msg: `your language: ${lang}` }; }, );

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.

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

When defining cookies, you can specify the type using the generic parameter:

interface UserPreferences { // Cookies with different types userId: Cookie<number, "userId">; darkMode: Cookie<boolean, "darkMode">; lastVisit: Cookie<Date, "lastVisit">; language: Cookie<string, "language">; // Using omitted type parameter (implicitly string) theme: Cookie<"theme">; } export const savePreferences = api<UserPreferences, void>({ 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... });

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:

// 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.