PAYATHON 2026

Encore.ts 能否在认证网关中直接清除过期会话的 Cookie?

数据阿明

结论

不能直接通过 Encore.ts 的 authHandler 清除浏览器 Cookie。它负责返回认证数据或抛出认证错误,不提供用于修改客户端 HTTP 响应的响应对象。清理 Cookie 应放在能够返回响应的 API endpoint 或 middleware 中。

对于设置了 auth: true 的接口,认证失败后,客户端可以调用一个无需认证的清理接口,让该接口通过响应使 Cookie 立即过期。

为什么抛出认证错误还不够?

服务端判定 session token 过期后,浏览器保存的 Cookie 不会自动删除。浏览器仍会按照 Cookie 自身的有效期继续发送它。

Encore 的认证流程也会影响清理代码能否执行:

  • auth handler 抛出 APIError.unauthenticated(...) 时,请求被视为未认证。
  • 目标接口要求 auth: true 时,网关会直接拒绝请求,不会进入目标接口及其服务 middleware。
  • 目标接口不要求认证时,请求仍可继续执行。
  • auth handler 抛出其他异常时,即使目标接口不要求认证,网关也会中止请求。

因此,即使清理接口无需认证,auth handler 也应在 token 过期时抛出 APIError.unauthenticated(...),以免其他异常使网关提前中止请求。参见 Encore 认证流程文档。

下面的示例假设 Cookie 名称为 session,创建时使用 Path=/,未设置 Domain,并通过 HTTPS 访问。实际使用时,应替换为应用中的名称和作用域。

import { api, Cookie } from "encore.dev/api";

interface ClearSessionResponse {
  session: Cookie<"session">;
}

export const clearSession = api(
  {
    expose: true,
    auth: false,
    method: "POST",
    path: "/auth/clear-session",
  },
  async (): Promise<ClearSessionResponse> => {
    return {
      session: {
        value: "",
        path: "/",
        maxAge: 0,
        httpOnly: true,
        secure: true,
        sameSite: "Lax",
      },
    };
  },
);

Encore 支持在 API 响应类型中使用 Cookie<"名称">,并配置 maxAge、path、domain 等属性。上面的接口通过响应 Cookie 发出删除指令。参见 Encore Cookie 文档。

客户端确认会话无效后调用该接口。同源部署时,例如可以使用:

const response = await fetch("/auth/clear-session", {
  method: "POST",
  credentials: "include",
});

if (!response.ok) {
  throw new Error("Failed to clear session cookie");
}

建议将调用放在统一的会话失效处理逻辑中,避免多个失败请求反复触发清理。如果已有 session refresh 流程,应先确定刷新失败,再清理会话并引导用户重新登录。

可以通过 middleware 自动清理吗?

可以,但请求必须能够到达服务。对于允许匿名访问的接口,middleware 可以在 await next(req) 后检查 getAuthData(),并通过 resp.header.add("Set-Cookie", ...) 添加删除 Cookie 的响应头。middleware 需要注册到对应的 Service。

这种方法无法覆盖已被网关拒绝的 auth: true 请求。另外,getAuthData() === null 只表示没有认证数据,无法单独证明 token 已过期。不要把清理逻辑无条件应用到所有匿名接口,尤其要避免覆盖登录接口刚设置的新 Cookie。相关响应头 API 见 Encore middleware 文档。

删除 Cookie 时,需要返回同名 Cookie,匹配原来的 Path 和 Domain,并设置 Max-Age=0 或过去的 Expires。仅将值设为空字符串不会删除 Cookie。HttpOnly Cookie 也需要由服务端响应清理,页面脚本无法通过 document.cookie 修改它。参见 MDN Cookie 文档。

还应检查以下条件:

  • 示例中的 secure: true 面向 HTTPS;本地 HTTP 调试时需按实际环境调整。
  • 跨域调用需要携带 credentials,并配置允许凭据的 CORS;跨站请求还会受到 SameSite 和浏览器 Cookie 策略限制。
  • 在浏览器开发者工具中确认清理响应包含 Set-Cookie,并检查后续请求是否仍携带旧 Cookie。
  • 如果清理接口同时承担完整退出登录功能,还应按会话存储方式撤销服务端 session;删除浏览器 Cookie 只处理客户端状态。

备注:内容仅供参考。