mcpField
O
oauth

oauth

github.com/val-town开发1041 次安装5 周前更新
代码仓库

关于 oauth

oauth 技能介绍 Val Town 的 std/oauth 中间件,用于为 Hono 应用添加 Val Town 账户登录。它说明如何自动管理登录、登出和会话,无需在应用中配置提供方或会话存储。

主要功能

  1. 01用 OAuth 中间件封装 Hono fetch 处理器
  2. 02添加托管的登录、回调和登出路由
  3. 03读取已认证用户的会话数据
  4. 04在加密 Cookie 中保存会话

适用场景

  1. 01为 Hono 应用添加 Val Town 账户登录
  2. 02根据当前会话限制路由访问
  3. 03验证未认证请求的重定向或 401 响应

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/val-town/plugins --skill oauth

安装后在 Claude Code 中输入/oauth确认已加载。

详细介绍

OAuth (std/oauth)

Val Town 通过 std/oauth 提供零配置的“使用 Val Town 登录”。无需设置数据库或配置提供方,只需封装 Hono fetch 处理函数,即可免费获得登录、注销和会话管理功能。会话存储在加密 Cookie 中,有效期为 30 天。

这仅适用于 Val Town 账户登录。如需使用 Google / GitHub / Slack / 等服务的 OAuth,请参阅 third-party-integrations 技能,其中按服务记录了相应流程。

如果目标是让团队内部使用应用,而不是让应用拥有自己的登录用户,那么限制该 val 的应用访问权限是更简单的方案——平台会在代码运行前拦截端点,无需编写任何身份验证代码。请参阅 restricted-access 技能。不要在同一个 val 上同时使用两者:同时受限且运行 oauthMiddleware 的 val 会让访客进行两次身份验证。

导入

import {
  getOAuthUserData,
  oauthMiddleware,
} from "https://esm.town/v/std/oauth/middleware.ts";

封装应用

oauthMiddleware(handler) 接收 Hono fetch 处理函数,并返回一个封装后的处理函数,该函数会注入三个自动管理的路由:

  • GET /auth/login — 启动登录流程
  • GET /auth/callback — 完成登录流程
  • POST /auth/logout — 清除会话

将封装后的处理函数导出为 val 的默认导出:

import { Hono } from "npm:hono";
import { oauthMiddleware } from "https://esm.town/v/std/oauth/middleware.ts";

const app = new Hono();
app.onError((err) => Promise.reject(err));

app.get("/", (c) => c.text("hello"));

export default oauthMiddleware(app.fetch);

无需自行编写 /auth/* 路由——中间件会添加这些路由。不要在自己的应用中覆盖它们。

读取当前用户

可在任意路由中调用 getOAuthUserData(rawRequest)。在 Hono 中,rawRequest 是 c.req.raw。如果请求已通过身份验证,它会返回会话数据;否则返回 null。

interface SessionData {
  user: {
    id: string;
    username: string | null;
    email: string | null;
    bio: string | null;
    tier: "free" | "pro" | null;
    type: "user" | "org";
    url: string;
    links: {
      self: string;
      profileImageUrl: string | null;
    };
  };
  accessToken: string; // Val Town API token (act on behalf of the user)
  refreshToken?: string;
  idToken?: string;
  expiresAt: number; // Unix timestamp (ms)
  isOrgMember?: boolean; // true if user belongs to this val's org
}
app.get("/", async (c) => {
  const session = await getOAuthUserData(c.req.raw);
  if (session?.user) {
    return c.html(
      `<p>Logged in as ${session.user.username}</p>` +
      `<form method="POST" action="/auth/logout"><button>Log out</button></form>`
    );
  }
  return c.html(`<a href="/auth/login">Log in with Val Town</a>`);
});

限制路由访问

没有内置的“要求登录”辅助工具——可通过检查 getOAuthUserData 来限制路由访问,并在会话缺失时返回 401 或重定向到 /auth/login:

app.get("/dashboard", async (c) => {
  const session = await getOAuthUserData(c.req.raw);
  if (!session?.user) return c.redirect("/auth/login");
  return c.html(`<h1>Welcome ${session.user.username}</h1>`);
});

无需配置的内容

  • 无需环境变量——凭据和重定向 URL 均由平台处理。
  • 无需设置回调 URL——/auth/callback 会自动配置。
  • 无需会话存储——会话保存在加密 Cookie 中。

验证更改

添加 OAuth 后,对受限路由调用 fetch_val_endpoint,确认未通过身份验证时会触发重定向或返回 401。完整登录流程需要真实的浏览器会话,无法仅通过 fetch_val_endpoint 测试——分享线上 URL,并请用户尝试登录。

评论

支持 Markdown