# Cookies (/docs/concepts/cookies)

了解 Better Auth 如何使用 cookies，包括 cookie 前缀、自定义 cookie 属性、跨子域共享、安全 cookies，以及使用代理处理 Safari ITP。



Cookies 用于存储会话令牌、会话数据、OAuth 状态等数据。

* 主要的 `session_token` Cookie 仍然是不透明的、使用密钥签名的会话标识符
* 仅当启用 `session.cookieCache` 时才会存在 `session_data` Cookie，其编码取决于配置的策略：
  * `compact`：base64url + 使用您的 Better Auth 密钥进行 HMAC
  * `jwt`：默认为 HS256，或者在 JWT 插件上启用 `sessionCookieCache` 时使用非对称签名
  * `jwe`：使用您的 Better Auth 密钥加密

如果您使用[版本化密钥](/docs/reference/options#secrets)进行轮换，依赖密钥的 Cookie 数据（包括签名 Cookie 和加密的 JWE 会话缓存）将自动使用当前密钥，并在受支持的情况下继续兼容之前的密钥。

### Cookie 前缀 [#cookie-前缀]

默认情况下，Better Auth 的 Cookies 格式为 `${prefix}.${cookie_name}`。默认前缀是“better-auth”。您可以通过在认证选项的 `advanced` 对象中设置 `cookiePrefix` 来更改前缀。

```ts title="auth.ts"
import { betterAuth } from "better-auth"

export const auth = betterAuth({
    advanced: {
        cookiePrefix: "my-app"
    }
})
```

### 自定义 Cookies [#自定义-cookies]

在服务器运行于生产模式时，所有 Cookies 都是 `httpOnly` 和 `secure` 的。

如果您想设置自定义 Cookie 名称和属性，可以通过在认证选项的 `advanced` 对象中设置 `cookies` 来实现。

默认情况下，Better Auth 使用以下 Cookies：

* `session_token` 用于存储会话令牌
* `session_data` 用于在启用 Cookie 缓存时存储会话数据
* `dont_remember` 用于存储当 `rememberMe` 被禁用时的标志

插件也可能使用 Cookies 来存储数据。例如，双因素认证插件使用 `two_factor` Cookie 来存储双因素认证状态。

```ts title="auth.ts"
import { betterAuth } from "better-auth"

export const auth = betterAuth({
    advanced: {
        cookies: {
            session_token: {
                name: "custom_session_token",
                attributes: {
                    // 设置自定义 Cookie 属性
                }
            },
        }
    }
})
```

### 跨子域 Cookies [#跨子域-cookies]

有时您可能需要在子域之间共享 Cookies。
例如，如果您对 `auth.example.com` 进行身份验证，您可能也希望在同一会话中访问 `app.example.com`。

<Callout type="warn">
  `domain` 属性控制哪些域可以访问 Cookie。将其设置为根域（例如 `example.com`）会使 Cookie 在所有子域中可访问。为了安全起见，请遵循以下指南：

  1. 仅在必要时启用跨子域 Cookies
  2. 将域设置为所需的最具体范围（例如 `app.example.com` 而不是 `.example.com`）
  3. 小心对待可能访问这些 Cookie 的不可信子域
  4. 考虑为不可信服务使用单独的域（例如 `status.company.com` 而不是 `app.company.com`）
</Callout>

```ts title="auth.ts"
import { betterAuth } from "better-auth"

export const auth = betterAuth({
    advanced: {
        crossSubDomainCookies: {
            enabled: true,
            domain: "app.example.com", // 您的域名
        },
    },
    trustedOrigins: [
        'https://example.com',
        'https://app1.example.com',
        'https://app2.example.com',
    ],
})
```

### 安全 Cookies [#安全-cookies]

默认情况下，只有在服务器运行于生产环境时，Cookies 才是安全的。您可以通过在认证选项的 `advanced` 对象中设置 `useSecureCookies` 为 `true`，强制 Cookies 始终使用安全模式。

```ts title="auth.ts"
import { betterAuth } from "better-auth"

export const auth = betterAuth({
    advanced: {
        useSecureCookies: true
    }
})
```

## Safari、ITP 与跨域设置 [#safariitp-与跨域设置]

Safari 内置了一个隐私功能，称为智能追踪防护（Intelligent Tracking Prevention，简称 ITP），会阻止第三方 Cookies。

如果您的 Better Auth API 托管在与前端不同的域名下，Safari 可能完全阻止身份验证 Cookies。

以下示例在 Safari 中会失败：

```
前端: https://app.domainB.com
API:   https://domainA.com
```

如果您的前端发起类似以下请求：

```ts
fetch("https://domainA.com/api/auth/get-session", {
  credentials: "include"
})
```

Safari 会将 `domainA.com` 视为第三方，并阻止其 Cookies。这可能导致会话无法持久化，`Set-Cookie` 头被忽略，用户在登录后依然显示未登录状态，或是在 Chrome 中工作正常但 Safari 中失败。

要解决此问题，有两种方案：

1. 使用反向代理将请求代理到 API
2. 使用共享父域名

### 使用反向代理 [#使用反向代理]

您可以通过与前端相同域名的反向代理来访问 API，而不是直接调用它。

例如，而不是直接调用：

```
https://domainA.com/api/auth/*
```

您可以调用：

```
https://app.domainB.com/api/auth/*
```

然后配置您的托管服务，将请求代理到实际的 API 服务器。

这样，请求在 Safari 中被视为同源请求，从而允许 Cookies 正常工作。

#### Netlify 示例 [#netlify-示例]

```toml title="netlify.toml"
[[redirects]]
  from = "/api/*"
  to = "https://domainA.com/api/:splat"
  status = 200
  force = true
```

#### Vercel 示例 [#vercel-示例]

```ts title="vercel.json"
{
  "rewrites": [
    {
      "source": "/api/:path*",
      "destination": "https://domainA.com/api/:path*"
    }
  ]
}
```

### 使用共享父域名 [#使用共享父域名]

您也可以使用共享的父域名来允许 Cookies 跨子域共享：

```
https://app.example.com
https://api.example.com
```

然后启用跨子域 Cookies 并设置域为：

```ts title="auth.ts"
import { betterAuth } from "better-auth"

export const auth = betterAuth({
    advanced: {
        crossSubDomainCookies: {
            enabled: true,
            domain: "example.com",
        },
    },
})
```

有关跨子域 Cookies 的更多信息，请参见[上述文档](#cross-subdomain-cookies)。

这将避免 Safari 将 API 视为第三方。

