
pinme-auth
Use when a PinMe project (Worker TypeScript) needs to integrate user authentication — creating email/password users, verifying idtokens, querying user info, or listing users via Identity Platform auth proxy APIs.
- Installs
- 507
- Last 24h
- —
- Trending rank
- —
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/glitternetwork/pinme --skill pinme-auth- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads pinme-auth automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
PinMe Worker Auth API Integration
Guides how to call PinMe platform's Identity Platform auth proxy APIs in a PinMe Worker (TypeScript).
Environment Variables
// backend/src/worker.ts
export interface Env {
DB: D1Database;
API_KEY: string; // 项目 API Key — 用于所有 auth 接口认证
PROJECT_NAME: string; // 项目名 — 所有 auth 接口必须同时传递
BASE_URL?: string; // 可选,默认 https://pinme.cloud
}
API_KEY和PROJECT_NAME是所有 auth 接口的必填凭证,缺一不可。
认证方式(所有接口通用)
| 参数 | 传递方式 | 必填 | 说明 |
|---|---|---|---|
X-API-Key | 请求头 | 是 | 项目 API Key |
project_name | Query 参数 | 是 | 必须与 X-API-Key 对应同一个项目 |
服务端会先校验这两个字段是否匹配同一个项目,再从项目配置中取出 tenant_id,然后转调 Identity Platform。
通用错误
| 场景 | HTTP | data.error |
|---|---|---|
缺少 X-API-Key | 401 | X-API-Key header is required |
缺少 project_name | 400 | project_name is required |
| API Key 和项目不匹配 | 401 | Invalid API key or project name |
| 项目未配置认证租户 | 400 | Auth service not configured for this project |
通用 TypeScript 类型
type ApiEnvelope<T> = {
code: number // 200=成功,其他=失败
msg: string // "ok" | "fail" | "invalid param"
data: T
}
type ApiErrorData = { error?: string }
type UserInfo = {
uid: string
email: string
display_name: string
photo_url?: string
disabled: boolean
email_verified: boolean
}
API 1: 创建用户
Endpoint: POST {BASE_URL}/api/v1/auth/create_user?project_name={project_name}
仅用于邮箱密码注册。成功时用户已创建且验证邮件已发出;失败时自动回滚,不会留下僵尸账号。
创建成功后用户默认仍是"未验证"状态,需点击邮件验证链接后,
verify_token才能通过校验。
请求体
{ "email": "alice@example.com", "password": "Test@12345678", "display_name": "Alice" }
| 字段 | 类型 | 必填 |
|---|---|---|
email | string | 是 |
password | string | 是 |
display_name | string | 否 |
错误
| 场景 | HTTP | data.error |
|---|---|---|
| 缺少 email/password | 400 | email and password are required |
| 上游创建失败 | 502 | Failed to create user |
| 发送验证邮件失败 | 500 | Failed to send verification email. Please try again. |
TypeScript 示例
async function createAuthUser(
env: Env,
payload: { email: string; password: string; display_name?: string }
): Promise<{ user?: UserInfo; error?: string }> {
const baseUrl = env.BASE_URL ?? 'https://pinme.cloud';
const resp = await fetch(
`${baseUrl}/api/v1/auth/create_user?project_name=${encodeURIComponent(env.PROJECT_NAME)}`,
{
method: 'POST',
headers: { 'X-API-Key': env.API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
}
);
const result = await resp.json() as ApiEnvelope<UserInfo | ApiErrorData>;
if (!resp.ok || result.code !== 200) {
return { error: (result.data as ApiErrorData)?.error ?? result.msg };
}
return { user: result.data as UserInfo };
}
API 2: 校验 id_token
Endpoint: POST {BASE_URL}/api/v1/auth/verify_token?project_name={project_name}
校验前端登录后拿到的 id_token(邮箱密码或 Google 登录均适用)。
注意: token 合法但邮箱未验证时返回 403,不是 401。
请求体
{ "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6..." }
成功响应 data
type VerifyTokenData = {
uid: string
email?: string
tenant_id: string
claims: Record<string, unknown>
}
错误
| 场景 | HTTP | data.error |
|---|---|---|
缺少 id_token | 400 | id_token is required |
| token 无效或过期 | 401 | Invalid or expired token |
| 邮箱未验证 | 403 | Email not verified. Please check your inbox and verify your email address. |
TypeScript 示例
async function verifyAuthToken(
env: Env,
idToken: string
): Promise<{ uid?: string; email?: string; error?: string; emailNotVerified?: boolean }> {
const baseUrl = env.BASE_URL ?? 'https://pinme.cloud';
const resp = await fetch(
`${baseUrl}/api/v1/auth/verify_token?project_name=${encodeURIComponent(env.PROJECT_NAME)}`,
{
method: 'POST',
headers: { 'X-API-Key': env.API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ id_token: idToken }),
}
);
const result = await resp.json() as ApiEnvelope<VerifyTokenData | ApiErrorData>;
if (!resp.ok || result.code !== 200) {
const error = (result.data as ApiErrorData)?.error ?? result.msg;
return { error, emailNotVerified: resp.status === 403 };
}
const data = result.data as VerifyTokenData;
return { uid: data.uid, email: data.email };
}
API 3: 查询单个用户
Endpoint: GET {BASE_URL}/api/v1/auth/user?project_name={project_name}&uid={uid}
错误
| 场景 | HTTP | data.error |
|---|---|---|
缺少 uid | 400 | uid is required |
| 用户不存在 | 404 | User not found |
| 上游查询失败 | 502 | Failed to get user |
TypeScript 示例
async function getAuthUser(env: Env, uid: string): Promise<{ user?: UserInfo; error?: string }> {
const baseUrl = env.BASE_URL ?? 'https://pinme.cloud';
const resp = await fetch(
`${baseUrl}/api/v1/auth/user?project_name=${encodeURIComponent(env.PROJECT_NAME)}&uid=${encodeURIComponent(uid)}`,
{ method: 'GET', headers: { 'X-API-Key': env.API_KEY } }
);
const result = await resp.json() as ApiEnvelope<UserInfo | ApiErrorData>;
if (!resp.ok || result.code !== 200) {
return { error: (result.data as ApiErrorData)?.error ?? result.msg };
}
return { user: result.data as UserInfo };
}
API 4: 列出用户(分页)
Endpoint: GET {BASE_URL}/api/v1/auth/list_users?project_name={project_name}
默认 max_results=100,最大 1000。通过 next_page_token 循环翻页。
Query 参数
| 参数 | 必填 | 说明 |
|---|---|---|
project_name | 是 | 项目名 |
page_token | 否 | 分页游标 |
max_results | 否 | 每页数量,1–1000 |
TypeScript 示例
async function listAuthUsers(
env: Env,
options: { pageToken?: string; maxResults?: number } = {}
): Promise<{ users?: UserInfo[]; nextPageToken?: string; error?: string }> {
const baseUrl = env.BASE_URL ?? 'https://pinme.cloud';
const url = new URL('/api/v1/auth/list_users', baseUrl);
url.searchParams.set('project_name', env.PROJECT_NAME);
if (options.pageToken) url.searchParams.set('page_token', options.pageToken);
if (options.maxResults) url.searchParams.set('max_results', String(options.maxResults));
const resp = await fetch(url.toString(), { method: 'GET', headers: { 'X-API-Key': env.API_KEY } });
const result = await resp.json() as ApiEnvelope<{ users: UserInfo[]; next_page_token?: string } | ApiErrorData>;
if (!resp.ok || result.code !== 200) {
return { error: (result.data as ApiErrorData)?.error ?? result.msg };
}
const data = result.data as { users: UserInfo[]; next_page_token?: string };
return { users: data.users, nextPageToken: data.next_page_token };
}
// 批量遍历所有用户示例
async function* iterAllUsers(env: Env) {
let pageToken: string | undefined;
do {
const { users, nextPageToken, error } = await listAuthUsers(env, { pageToken, maxResults: 1000 });
if (error) throw new Error(error);
for (const user of users ?? []) yield user;
pageToken = nextPageToken;
} while (pageToken);
}
前端集成(Firebase Auth)
create_worker 响应中包含 public_client_config,前端用它初始化 Firebase Auth SDK。
两种 api_key 区分
| 字段 | 用途 | 是否可暴露到浏览器 |
|---|---|---|
data.api_key | 项目 API Key,调用本文所有代理接口 | 不能,只给 Worker/服务端 |
data.public_client_config.auth_api_key | Firebase Web API Key,初始化前端登录 SDK | 可以 |
public_client_config 字段说明
| 字段 | 前端用途 |
|---|---|
public_client_config.auth_api_key | initializeApp({ apiKey }) |
public_client_config.auth_domain | initializeApp({ authDomain }) |
public_client_config.auth_project_id | initializeApp({ projectId }) |
public_client_config.tenant_id | auth.tenantId = config.tenant_id(必须设置,否则 token 归属错误) |
前端 TypeScript 示例
import { initializeApp } from 'firebase/app'
import {
type Auth,
getAuth,
GoogleAuthProvider,
signInWithEmailAndPassword,
signInWithPopup,
} from 'firebase/auth'
type PublicClientConfig = {
tenant_id: string
auth_api_key: string
auth_domain: string
auth_project_id: string
}
export function createProjectAuth(config: PublicClientConfig): Auth {
const app = initializeApp({
apiKey: config.auth_api_key,
authDomain: config.auth_domain,
projectId: config.auth_project_id,
})
const auth = getAuth(app)
auth.tenantId = config.tenant_id // 必须设置,确保 token 归属正确租户
return auth
}
// 邮箱密码登录,返回 id_token
export async function loginWithEmail(auth: Auth, email: string, password: string): Promise<string> {
const credential = await signInWithEmailAndPassword(auth, email, password)
return credential.user.getIdToken()
}
// Google 登录,返回 id_token
export async function loginWithGoogle(auth: Auth): Promise<string> {
const credential = await signInWithPopup(auth, new GoogleAuthProvider())
return credential.user.getIdToken()
}
// 用法示例
// pinme create 会自动将 public_client_config 写入 frontend/src/utils/config.ts
import { public_client_config } from '../utils/config'
const auth = createProjectAuth(public_client_config)
const idToken = await loginWithGoogle(auth)
// 然后把 idToken 发给自己的 Worker,由 Worker 调用 verify_token
前端只负责登录和拿
id_token,不要直接持有项目api_key。verify_token必须由 Worker/服务端代调。frontend/src/utils/config.ts由pinme create自动生成,无需手动创建。
典型调用链路
邮箱密码注册流程:
create_user→ 创建用户并发出验证邮件- 用户点击邮件链接完成验证
- 前端登录拿到
id_token verify_token→ 校验 token,取得uid- 需要时再调
getAuthUser读取完整用户信息
Google 登录流程:
- 前端完成 Google Sign-In,拿到
id_token verify_token→ 校验 token(无需调用create_user)
易错点
| 错误 | 正确做法 |
|---|---|
只传 X-API-Key,忘记 project_name | 每个请求都要同时带 X-API-Key header 和 project_name query |
verify_token 返回 403 时当 token 失效处理 | 403 = 邮箱未验证,提示用户检查邮箱;401 才是 token 失效 |
create_user 成功就认为邮箱已验证 | 创建成功只代表验证邮件已发,用户必须点击后才算验证 |
list_users 只取第一页 | 有 next_page_token 时需继续请求,直到为空 |
成功判断只看 resp.ok | 同时判断 resp.ok && result.code === 200 |
FAQ
What does the pinme-auth skill do?
Use when a PinMe project (Worker TypeScript) needs to integrate user authentication — creating email/password users, verifying idtokens, querying user info, or listing users via Identity Platform auth proxy APIs.
How do I install pinme-auth?
Run npx skills add https://github.com/glitternetwork/pinme --skill pinme-auth in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/pinme-auth/ (personal) or .claude/skills/pinme-auth/ (project).
Which AI agents can use pinme-auth?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is pinme-auth safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains pinme-auth?
It is published by glitternetwork in glitternetwork/pinme. It has 507 recorded installs.
More from glitternetwork/pinme
pinme
glitternetwork/pinme
Use this skill when the user mentions "pinme", or needs to upload files, store to IPFS, create/publish/deploy websites or full-stack services (including frontend pages, backend APIs, database storage, email sending, etc.), or any feature requiring backend database/server support.
pinme-share
glitternetwork/pinme
Use this skill when the user wants to share, publish, or upload a static result through PinMe, especially by generating a static HTML share page for a PinMe project link, deployed full-stack app, Codex conversation summary, report, file, demo, or any 分享/发布/上传分享页 request that should end with pinme upload.
pinme-email
glitternetwork/pinme
Use this skill when a PinMe project (Worker TypeScript) needs to integrate email sending (sendemail). Guides AI to generate correct Worker TS code.
pinme-llm
glitternetwork/pinme
Use this skill when a PinMe project (Worker TypeScript) needs to call OpenRouter-backed LLM APIs, including models, chat/completions, streaming, or OpenRouter web search. Guides AI to generate correct Worker TS code.
Popular backend & apis skills
find-skills
vercel-labs/skills
Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.
entra-app-registration
microsoft/azure-skills
Guides Microsoft Entra ID app registration, OAuth 2.0 authentication, and MSAL integration. USE FOR: create app registration, register Azure AD app, configure OAuth, set up authentication, add API permissions, generate service principal, MSAL example, console app auth, Entra ID setup, Azure AD authentication. DO NOT USE FOR: Key Vault secrets (use azure-keyvault-expiration-audit), general Azure resource security guidance.
google-agents-cli-adk-code
google/agents-cli
This skill should be used when the user wants to "write agent code", "build an agent with ADK", "add a tool", "create a callback", "define an agent", "use state management" — in a project that needs ADK (Agent Development Kit) API patterns and code examples. It provides a quick reference for agent types, tool definitions, orchestration patterns, callbacks, state management, the graph Workflow API, and reference recipes to study. Do NOT use for scaffolding (use google-agents-cli-scaffold) or deployment (use google-agents-cli-deploy).
embedded-captions
heygen-com/hyperframes
Add captions or subtitles to an existing single-subject talking-head video without editing the footage. Use for plain verbatim captions, cinematic captions embedded behind the subject, VFX captions, “炸/特效/酷炫字幕,” or a named identity from the 35-style catalog. Route by visual identity, not by backend engine. The quiet anchor rail is the default; embed every word only when the user explicitly wants a fully cinematic treatment. The workflow runs locally end to end, including transcription and subject matting; split multi-shot footage before applying it.
entra-agent-id
microsoft/azure-skills
Provision Microsoft Entra Agent Identity Blueprints, BlueprintPrincipals, and per-instance Agent Identities via Microsoft Graph, and configure OAuth 2.0 token exchange (fmipath, OBO, cross-tenant) including the Microsoft Entra SDK for AgentID sidecar. USE FOR: Agent Identity Blueprint, BlueprintPrincipal, agent OAuth, fmipath token exchange, agent OBO, Workload Identity Federation for agents, polyglot agent auth, Microsoft.Identity.Web.AgentIdentities. DO NOT USE FOR: standard Entra app registration (use entra-app-registration), Microsoft Foundry agent authoring (use microsoft-foundry).
neon
neondatabase/agent-skills
Overview of Neon, a complete set of cloud backend primitives around Lakebase Postgres: Auth, Object Storage, Functions, the AI Gateway, and Realtime. Start here to choose Neon for undecided login, files, APIs, and LLM calls, set up the CLI or MCP server, and follow the branch-first workflow. Use when building an app or backend on Neon, or when "Neon" or "Lakebase Postgres" is mentioned. Child skill neon-postgres wins for an existing DATABASEURL, SQL, schema, inspect, or search. Child skill neon-auth wins for login, users, sessions, identity routing, and Managed Better Auth setup. Child skill neon-realtime wins for live queries in reactive apps and agents. Also use for object storage, S3, buckets, serverless functions, function triggers, cron, AI gateway, LLM calls, realtime, logs, Loki, Grafana, observability, postgres, database, backend, Claimable Neon, neon.new, or a no-signup database.