oauth
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseOAuth (std/oauth)
OAuth (std/oauth)
Val Town provides zero-config "Log in with Val Town" via . No database setup, no provider config — wrap your Hono fetch handler and you get login, logout, and session management for free. Sessions are stored in encrypted cookies and last 30 days.
std/oauthThis is for Val Town account login only. For Google / GitHub / Slack / etc. OAuth, see the skill — those flows are documented per-service.
third-party-integrationsIf the goal is to keep an app internal to a team rather than to give it its own logged-in users, restricting the val's app access is the simpler answer — the platform gates the endpoint before your code runs, and you write no auth code. See the skill. Don't apply both to one val: a restricted val that also runs makes visitors authenticate twice.
restricted-accessoauthMiddlewareVal Town 通过 提供零配置的“使用 Val Town 登录”功能。无需设置数据库,也无需配置提供商——只需包装 Hono fetch handler,即可开箱获得登录、注销和会话管理功能。会话存储在加密 Cookie 中,有效期为 30 天。
std/oauth此功能仅用于 Val Town 账户登录。如需使用 Google、GitHub、Slack 等第三方 OAuth,请参阅 skill,其中按服务分别记录了相关流程。
third-party-integrations如果目标是将应用限制为团队内部使用,而不是为应用创建自己的登录用户,那么限制 val 的应用访问权限是更简单的方案——平台会在代码运行前拦截端点,你无需编写任何身份验证代码。请参阅 skill。不要同时对同一个 val 应用这两种方案:受限 val 如果还运行 ,会导致访问者进行两次身份验证。
restricted-accessoauthMiddlewareImports
导入
ts
import {
getOAuthUserData,
oauthMiddleware,
} from "https://esm.town/v/std/oauth/middleware.ts";ts
import {
getOAuthUserData,
oauthMiddleware,
} from "https://esm.town/v/std/oauth/middleware.ts";Wrapping your app
包装应用
oauthMiddleware(handler)- — starts the login flow
GET /auth/login - — completes the login flow
GET /auth/callback - — clears the session
POST /auth/logout
Export the wrapped handler as the val's default:
ts
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);You don't write the routes yourself — the middleware adds them. Don't shadow them in your own app.
/auth/*oauthMiddleware(handler)- ——启动登录流程
GET /auth/login - ——完成登录流程
GET /auth/callback - ——清除会话
POST /auth/logout
将包装后的 handler 导出为 val 的默认导出:
ts
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/*Reading the current user
读取当前用户
Call from any route. In Hono, is . It returns the session data if the request is authenticated, or otherwise.
getOAuthUserData(rawRequest)rawRequestc.req.rawnullts
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
}ts
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>`);
});可以从任意路由调用 。在 Hono 中, 是 。如果请求已通过身份验证,它会返回会话数据,否则返回 。
getOAuthUserData(rawRequest)rawRequestc.req.rawnullts
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
}ts
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>`);
});Gating routes
为路由设置访问控制
There's no built-in "require login" helper — gate routes by checking and returning a 401 or redirecting to when the session is missing:
getOAuthUserData/auth/logints
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>`);
});没有内置的“要求登录”辅助函数——可以通过检查 来保护路由;当会话不存在时,返回 401 或重定向到 :
getOAuthUserData/auth/logints
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>`);
});What you don't need to configure
无需配置的内容
- No env vars — credentials and redirect URLs are handled by the platform.
- No callback URL setup — is wired automatically.
/auth/callback - No session store — sessions live in encrypted cookies.
- 无需环境变量——凭据和重定向 URL 均由平台处理。
- 无需设置回调 URL——已自动连接。
/auth/callback - 无需会话存储——会话保存在加密 Cookie 中。
Verifying changes
验证变更
After adding OAuth, call on a gated route to confirm it redirects or 401s when unauthenticated. The full login flow requires a real browser session and can't be exercised by alone — share the live URL and have the user try logging in.
fetch_val_endpointfetch_val_endpoint添加 OAuth 后,对受保护的路由调用 ,确认未通过身份验证的请求会被重定向或返回 401。完整的登录流程需要真实的浏览器会话,无法仅通过 测试——请分享在线 URL,并让用户尝试登录。
fetch_val_endpointfetch_val_endpoint