@qfeius/make-app-auth
v0.1.2
Published
Browser SDK for Make generated app authentication through make-gateway.
Readme
Make App Auth SDK
@qfeius/make-app-auth 是 Make 生成 App 的浏览器认证 SDK。
它只做薄封装:
- 检查当前 App 会话:
GET /api/make/auth/current-context - 未登录时按网关返回的
authorizationUrl跳转 Org 登录 - Org 回调由 make-gateway 直接换 token,并 302 到 App 域名下的 session complete 接口落
make_app_session - 退出账号:调用网关退出接口,由 make-gateway 后端清 Org 委托 token 和当前 App 会话,再回到 App 入口复用登录判断
- 业务请求遇到 401/403 时给出统一处理
- 当后端明确关闭统一登录时,改用调用方指定 token 或本地 makecli credentials token
SDK 不保存 Org token,不拼接 Org OAuth 参数,不负责 OAuth code exchange,不解析可信身份头。认证复杂逻辑仍在 make-gateway。token 模式只用于后端显式关闭统一登录的场景。
安装
公共 npm 依赖:
pnpm add @qfeius/make-app-auth --registry=https://registry.npmjs.org/本地联调:
pnpm add /Users/apple/code/make/make-app-auth-sdk最小接入
import { createMakeAppAuth } from '@qfeius/make-app-auth';
const auth = createMakeAppAuth({
gatewayBaseUrl: '/api/make',
apiAuthRedirect: true
});
const result = await auth.init({ redirect: true });
if (result.status === 'authenticated') {
renderApp({
auth,
context: result.context
});
} else if (result.status === 'redirecting') {
renderLoading();
} else if (result.reason === 'state_expired' || result.reason === 'challenge_expired') {
renderLoginExpired({
message: result.message || '登录已过期,请重新登录',
onRelogin: () => auth.login({ redirect: true })
});
} else if (result.status === 'forbidden') {
renderForbidden();
} else {
await auth.login({ redirect: true });
}init 是生成 App 的推荐启动入口。它会访问:
GET /api/make/auth/current-context?return_url=当前页面地址返回含义:
authenticated:已有当前 App 会话,可以渲染页面。authenticated + context.authMode="token":后端关闭统一登录,SDK 已切到 token 模式。redirecting:未登录且已跳转到网关返回的authorizationUrl。unauthenticated:未登录,但调用方指定了redirect: false或跳转保护已触发。unauthenticated + reason="state_expired" / "challenge_expired":登录过程已过期,页面应提示“登录已过期,请重新登录”,用户点击后调用auth.login({ redirect: true })。forbidden:已登录但无权访问当前 App。failed:网关返回了非预期错误。
如果只需要页面可见的精简运行态信息,也可以继续使用:
const runtimeView = await auth.getRuntimeView();如果需要当前用户、租户、App 上下文,使用:
const context = await auth.getCurrentContext();登录回调链路
正式链路下,Org OAuth redirect_uri 固定回到 make-gateway。make-gateway 会直接用 code 换 Org token,生成一次性 login_ticket,再跳到当前 App 域名下:
GET /api/make/auth/session/complete?login_ticket=...这个请求由 App 域名代理到 make-gateway。网关消费 login_ticket 后写入 make_app_session,再 302 回原始 App 页面。
因此,新 App 不需要主动调用 handleOAuthCallback(),init() 默认也不会处理 URL 上的 code/state,避免把业务参数误判成 OAuth 回调。
这个方法只作为旧链路兼容保留:如果页面 URL 里仍出现旧版 OAuth 回调参数,可以显式开启 legacy 模式完成旧版 exchange。
await auth.init({ legacyOAuthCallback: true });POST /api/make/oauth/token/exchange业务请求
业务接口继续统一走 make-gateway:
const records = await auth.api.post('/data/v1/record', {
app: 'expense',
entity: 'reimbursement',
fields: [],
pagination: { page: 1, size: 10 }
}, {
headers: {
'X-Make-Target': 'MakeService.ListResources'
}
});auth.api 是生成 App 的推荐业务请求入口,会默认补 credentials: 'include'、Accept: application/json,并对普通对象自动 JSON 序列化。
调用方可以在 init.headers 里传业务需要的 header,例如 X-Make-Target、X-Trace-Id、X-Idempotency-Key,也可以覆盖默认 Accept 或 Content-Type。
设置 apiAuthRedirect: true 后,统一登录模式下业务请求遇到 401/403 会先复用 auth.login({ redirect: true }) 获取网关登录挑战并跳转;如果跳转保护已触发或网关没有返回登录挑战,SDK 仍会抛出对应错误,避免无限循环。token 模式不会跳 Org。
如果 App 采用 Service 承接业务编排,业务路径也应继续放在 gatewayBaseUrl 作用域内,例如:
await auth.api.get('/app/schema');
await auth.api.post('/app/records/customer', payload);这类请求的浏览器链路是:
UI -> /api/make/app/** -> App Service -> make-gateway /make/meta|data/**认证链路仍是:
UI -> /api/make/auth/** -> App Service proxy -> make-gateway /api/make/auth/**Service 代理 /api/make/auth/session/complete 时必须保留网关返回给浏览器的 302 + Set-Cookie + Location,不要在 Service 内部跟随重定向。
如果后端返回统一登录关闭标记,SDK 会进入 token 模式,后续 auth.api 自动补:
Authorization: Bearer <token>token 来源优先级:
createMakeAppAuth({ accessToken })或tokentokenProvider()- Node/本地环境读取
credentialsPath,默认/Users/apple/.make/credentials等价的~/.make/credentials
浏览器不能直接读取本机文件,所以浏览器场景要通过 accessToken 或 tokenProvider 显式传入;credentials 文件兜底只适合 Node、本地调试或测试环境。
本地 vibe 项目如果尚未部署、没有 ngrok 域名,生成模板默认应关闭统一登录,继续用真实 Make 后端接口:
const auth = createMakeAppAuth({
gatewayBaseUrl: import.meta.env.VITE_MAKE_GATEWAY_BASE_URL || '/api/make',
unifiedLogin: false,
accessToken: import.meta.env.VITE_MAKE_ACCESS_TOKEN
});
const boot = await auth.init({ redirect: false });这种模式只用于本地调试。缺少 token 时不要跳 Org 登录页,应提示用户配置 VITE_MAKE_ACCESS_TOKEN 或 VITE_MAKE_TOKEN。只有显式配置 VITE_MAKE_AUTH_MODE=unified 或等价开关时才启用统一登录。
安全边界:
gatewayBaseUrl是 Make API 网关入口,不是统一登录地址;已发布 App 默认使用同源/api/make。- 业务代码应传相对路径,例如
/data/v1/record,SDK 会拼到gatewayBaseUrl下。 - 如果传入绝对 URL,SDK 只允许它落在
gatewayBaseUrl的同一 origin 和路径作用域内;否则拒绝请求,避免 token 模式下把Authorization发到外部域名。
列表没有过滤条件时不要传 filter 字段,尤其不要传 filter: []。需要过滤时再按业务条件追加:
const body = {
app: 'expense',
entity: 'reimbursement',
fields: [],
pagination: { page: 1, size: 10 }
};
if (keyword) {
body.filter = [{ title: { contains: keyword } }];
}
await auth.api.post('/data/v1/record', body, {
headers: {
'X-Make-Target': 'MakeService.ListResources'
}
});await auth.api.get('/meta/v1/schema?app=expense');
await auth.api.post('/data/v1/record', payload, {
headers: {
'X-Make-Target': 'MakeService.CreateRecord',
'X-Trace-Id': traceId
}
});
await auth.api.put('/data/v1/record/123', payload);
await auth.api.delete('/data/v1/record/123');底层仍保留 auth.fetch(path, init) / auth.request(path, init),用于少量需要完整控制 RequestInit 的场景。Vibe 生成代码默认应使用 auth.api,不要直接调用原生 window.fetch 访问 Make 后端。
退出
await auth.logout();默认语义是“退出账号”,不是只退出当前 App。SDK 会:
- 调
POST /api/make/auth/logout?return_url=...。 - make-gateway 在后端尽力调用 Org
/api/account/logout清理当前账号 token。 - 不管 Org 清理是否成功,make-gateway 都会清理当前 App 会话。
- make-gateway 返回受校验的
redirectUri。 - SDK 只按
redirectUri跳转,不拼接账号中心或 Org URL,也不再兼容旧orgSsoLogoutUrl。 - 页面再次启动时继续走
/auth/current-context,如果 Org 账号 token 已失效,会进入 Org 统一登录页。
默认 return_url 是当前域名根路径 /。如果 App 需要回到指定入口,可以显式传入:
await auth.logout({
returnUrl: window.location.origin + '/'
});注意:App 前端不自行拼 Org logout URL,也不处理 Org token;只调用 auth.logout()。退出后的跳转地址由 make-gateway 返回。
API
const auth = createMakeAppAuth({
gatewayBaseUrl: '/api/make',
currentContextPath: '/auth/current-context',
runtimeViewPath: '/auth/runtime-view',
exchangePath: '/oauth/token/exchange',
logoutPath: '/auth/logout',
apiAuthRedirect: true,
accessToken: undefined,
tokenProvider: undefined,
credentialsProfile: 'default',
credentialsPath: undefined
});方法:
init(options)login(options)loginGuard(options)getCurrentContext(options)getRuntimeView(options)handleOAuthCallback(options)exchangeCode({ code, state })logout(options)api.request(path, init)api.get(path, init)api.post(path, body, init)api.put(path, body, init)api.patch(path, body, init)api.delete(path, init)fetch(path, init)request(path, init)apiUrl(path)
错误类型:
MakeAppAuthErrorMakeAppUnauthorizedErrorMakeAppForbiddenError
调试 demo 同步
调试页是纯静态部署,为了部署时不依赖跨目录 import,会保留一份 vendored SDK 文件:
demo/vibe-auth-debug-app/sdk/make-app-auth.mjs修改 SDK 后执行:
pnpm --dir make-app-auth-sdk sync:demo接入 make-platform-skills
如果希望后续 Vibe App 由 Codex / make-platform-skills 生成时自动使用统一登录,需要把 SDK 接入规则固化到 makeui skill,而不是只写在单个 App 里。
推荐落地方式:
- 在
make-platform-skills/skills/makeui/SKILL.md增加 Make App 认证基线。 - 在
make-platform-skills/skills/makeui/references/auth-sdk-integration.md沉淀详细规则。 - 将同一份 skill 同步到本机已安装目录
/Users/apple/.codex/skills/makeui。 - 后续生成 Vibe App 时触发
makeuiskill,它会默认生成@qfeius/make-app-auth接入代码。
makeui 中建议固化的最小规则:
When generating a Make App frontend, wire authentication through `@qfeius/make-app-auth` by default.
Generated Vibe Apps should:
- depend on `@qfeius/make-app-auth`
- expose an explicit auth mode config: default local token, explicit unified login, or mock preview
- call `auth.init({ redirect: true })` in unified mode so unauthenticated users go to the Org login page
- not render an App-owned login page, login transition page, or signed-out completion page for unified login
- show a simple expired-login prompt when `auth.init()` returns `reason="state_expired"` or `reason="challenge_expired"`
- call `auth.login({ redirect: true })` only for expired-session re-login actions
- use `auth.api` for `/api/make/**` business requests
- call `await auth.logout()` for logout
- use `createMakeAppAuth({ unifiedLogin: false, accessToken })` when local token mode is selected
Generated Vibe Apps must not:
- read or persist Org tokens, `zs_session`, or `make_app_session`
- construct Org OAuth URLs, `redirect_uri`, `state`, or `code_challenge`
- handle Org OAuth `code`
- call Make backend with raw `window.fetch('/api/make/...')`
- monkey patch `window.fetch`
- send `filter: []` for unfiltered list requests可直接复制本仓库的指导文档作为 skill reference:
mkdir -p /Users/apple/code/make/make-platform-skills/skills/makeui/references
cp docs/skill-integration.md \
/Users/apple/code/make/make-platform-skills/skills/makeui/references/auth-sdk-integration.md同步到当前 Codex 已安装 skill:
mkdir -p /Users/apple/.codex/skills/makeui/references
cp /Users/apple/code/make/make-platform-skills/skills/makeui/SKILL.md \
/Users/apple/.codex/skills/makeui/SKILL.md
cp /Users/apple/code/make/make-platform-skills/skills/makeui/references/auth-sdk-integration.md \
/Users/apple/.codex/skills/makeui/references/auth-sdk-integration.md接入后建议检查:
rg -n "auth\\.fetch|auth\\.request\\(\\)|window\\.fetch\\('/api/make|filter:\\s*\\[\\]" \
/Users/apple/code/make/make-platform-skills/skills/makeui \
/Users/apple/.codex/skills/makeui这些关键词只应该出现在“禁止生成”的说明里,不应该出现在推荐代码示例里。
Vibe App 模板
SDK 内置一个最小模板:
make-app-auth-sdk/templates/vibe-app模板约定:
- unified 模式启动时调用
auth.init({ redirect: true }),未登录直接跳 Org 登录页。 - 会话过期后的重新登录只调用
auth.login({ redirect: true });不要生成退出完成页。 - 业务请求只通过
auth.api访问/api/make/**。 - 不在前端拼 Org OAuth URL,不处理
redirect_uri、code_challenge或code/state exchange。 - App 发布后必须放在平台统一管理的稳定域名下,且该域名能同源代理
/api/make/**到 make-gateway。
生成 App 推荐直接使用公共 npm 依赖:
{
"dependencies": {
"@qfeius/make-app-auth": "^0.1.2"
}
}发布
发布前检查:
pnpm --dir make-app-auth-sdk check公共 npm 发布方式:
pnpm --dir make-app-auth-sdk publish --registry=https://registry.npmjs.org/ --access public测试
pnpm --dir make-app-auth-sdk test
pnpm --dir make-app-auth-sdk check