@freebuff/auth

中文文档
0.1.0发布于 2026/10/07Apache-2.0TypeScriptES Module近 30 天下载 2.3万

Sign in with Freebuff: add Freebuff accounts to any site with no secrets. OIDC + PKCE for Cloudflare Workers, Bun, Node and Next.js.

原始使用文档
文档目录9 节
  1. 1. Get a client ID
  2. 2. Mount it
  3. Cloudflare Workers, Bun, Deno, Hono
  4. Next.js (App Router)
  5. Buttons and client state (React)
  6. The user
  7. Sessions and security
  8. Local development
  9. Options

Sign in with Freebuff

@freebuff/auth lets anyone with a Freebuff account sign in to your site: Google, GitHub or Apple through Freebuff, with nothing to configure and no secrets to keep. Your server learns who the visitor is (sub, and with their consent their email, name and picture). It never sees their password, provider credentials or Freebuff account token.

It is standard OpenID Connect (authorization code + PKCE) with a server-side session, and runs anywhere with fetch and Web Crypto: Cloudflare Workers, Bun, Node 20+, Deno and Next.js.

1. Get a client ID

Each project environment has its own public client ID, registered by the project's creator against exact callback URLs:

# Production: the site's real origin
npx @freebuff/auth register --project notes --name "Notes" \
  --environment production --redirect-uri https://notes.example/auth/freebuff/callback

# Local development: any port on localhost
npx @freebuff/auth register --project notes --name "Notes" \
  --environment development --redirect-uri http://localhost:8787/auth/freebuff/callback

It signs in as you with your Freebuff CLI login (or FREEBUFF_TOKEN) and prints FREEBUFF_CLIENT_ID. That, and your site's origin, are all the configuration there is. Neither is a secret. Re-running it is safe; add a new --redirect-uri when the site gets a new domain.

2. Mount it

Cloudflare Workers, Bun, Deno, Hono

Wrap your fetch handler. It serves the four auth routes, keeps sessions fresh, and makes getUser available anywhere inside:

import { createFreebuffAuth } from '@freebuff/auth'

const auth = createFreebuffAuth({
  clientId: env.FREEBUFF_CLIENT_ID,
  baseUrl: 'https://notes.example', // your canonical origin
})

export default {
  fetch: auth.wrap(async (request) => {
    const user = await auth.getUser(request)
    if (new URL(request.url).pathname.startsWith('/api/') && !user) {
      return Response.json({ error: 'Sign in required' }, { status: 401 })
    }
    return app.fetch(request)
  }),
}

See examples/cloudflare-worker.ts (static assets + API) and examples/hono.ts.

Next.js (App Router)

// lib/freebuff.ts
import { createFreebuffNext } from '@freebuff/auth/next'
export const freebuff = createFreebuffNext({
  clientId: process.env.FREEBUFF_CLIENT_ID!,
  baseUrl: process.env.APP_ORIGIN!,
})

// app/auth/freebuff/[...freebuff]/route.ts
export const { GET, POST } = freebuff.handlers

// proxy.ts (middleware.ts before Next 16): refreshes sessions before render
export const proxy = freebuff.proxy
export const config = { matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'] }

// Any Server Component, Route Handler or Server Action
const user = await freebuff.getUser()

See examples/nextjs.

Buttons and client state (React)

import { SignInWithFreebuff, SignOutButton, useFreebuffUser } from '@freebuff/auth/react'

<SignInWithFreebuff />                 // link to /auth/freebuff/signin, returns here
<SignOutButton returnTo="/" />         // a POST form; sign-out is never a link
const { user, isLoading } = useFreebuffUser() // reads /auth/freebuff/session

Without React: link to /auth/freebuff/signin?returnTo=/somewhere, sign out with <form method="post" action="/auth/freebuff/signout">, and read GET /auth/freebuff/session → { "user": { ... } | null }.

The user

interface FreebuffUser {
  sub: string            // always; stable for this visitor in this project
  email?: string         // `email` scope, when present
  email_verified?: boolean
  name?: string          // `profile` scope, when set
  picture?: string       // https URL
}
  • Key your data on sub. It is the same across your project's development and production clients, and different in every other project, so sites cannot correlate visitors by it. It never changes.
  • Email is profile data, not identity. It can change, may be absent, and may be unverified. Never merge or look up accounts by email.
  • Ask for less with scopes: ['openid'] (just sub) or ['openid', 'email'].

Sessions and security

  • No secrets anywhere in your project. Freebuff signs the tokens; your server verifies them with Freebuff's public keys (cached; no per-request network call).
  • The session is one __Host-freebuff_session cookie: HttpOnly, Secure, SameSite=Lax, host-only. It holds a one-hour access token and a refresh token. Tokens never reach page JavaScript.
  • Refresh tokens rotate on every use. A stolen, already-used refresh token ends the whole session. Parallel requests are safe: they receive the same successor.
  • Sessions last up to 30 days of inactivity and at most 90 days, then the visitor signs in again (usually one click: Freebuff remembers consent).
  • Sign-out is POST, same-origin only; it revokes the session at Freebuff.
  • If a Freebuff account is banned, or the project is disabled, its sessions stop within an hour (the access-token lifetime) and cannot be renewed.
  • Sign-in uses PKCE, state and nonce, pinned issuer, exact callback URLs, and RFC 9207 issuer checks. Token requests are refused from browsers.

getUser only refreshes inside wrap, the Next.js proxy, or the /auth/freebuff/session route, because a refreshed session must reach the browser or its next refresh looks like theft. Elsewhere it verifies the current access token and returns null once it expires.

Local development

Use your project's development client ID and allowInsecureLocalhost: true with a http://localhost:<port> or http://127.0.0.1:<port> baseUrl. Development clients accept any port on the registered loopback host. Never use a development client or allowInsecureLocalhost in production.

Options

OptionDefault
clientIdrequiredPublic, from provisioning
baseUrlrequiredCanonical origin; never derived from requests
issuerhttps://freebuff.com/oidcOnly for a non-production Freebuff
scopes['openid', 'email', 'profile']openid is always included
allowInsecureLocalhostfalseDevelopment only
fetchglobal fetchServer-side calls to Freebuff

For AI coding agents integrating this package, read AGENTS.md.

版本与发布记录

@freebuff/auth 共发布 1 个版本,首次发布于 2026/10/07;过去 12 个月发布了 1 个版本。

版本发布日期距今
0.1.0latest2026/10/071 个月前

关于 @freebuff/auth 的常见问题

@freebuff/auth 是什么?

Sign in with Freebuff: add Freebuff accounts to any site with no secrets. OIDC + PKCE for Cloudflare Workers, Bun, Node and Next.js.

如何安装 @freebuff/auth?

在项目目录运行 npm install @freebuff/auth,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 freebuff-auth,可以用 npx freebuff-auth 直接运行。

@freebuff/auth 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@freebuff/auth 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@freebuff/auth 可以商用吗?

@freebuff/auth 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@freebuff/auth 的下载量有多少?

根据 npm 官方下载统计,@freebuff/auth 在 2026/10/16 – 2026/11/14 这 30 天内被下载 22,946 次,日均约 765 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@freebuff/auth 还在维护吗?

最新版本 0.1.0 发布于 2026/10/07(1 个月前);至今共发布 1 个版本,其中过去 12 个月发布了 1 个;首次发布于 2026/10/07。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。