如何让 Claude Code、Codex 或 OpenClaw 帮你登录 Flashcards

现在大多数登录流程,依然默认所有初始化步骤都要由人亲手完成。

打开登录页。等验证码。复制令牌。手动创建 API 密钥。再把它粘贴进另一个工具。还得把文档解释给代理听。中途一旦出问题,又得自己收拾会话状态。

这类工作,本来就应该交给工具处理。

Flashcards 里,我们现在提供了一套开源的代理登录流程,起点就是一个发现入口 URL:

https://api.flashcards-open-source-app.com/v1/

这就是规范约定的标准入口。相同的发现响应也可以通过 https://api.flashcards-open-source-app.com/v1/agent 获取,但当前约定的起点是 /v1/

把这个 URL 交给 Claude Code、Codex 或 OpenClaw,代理就能自行理解流程、请求邮件验证码、完成校验、保存 API 密钥、读取账户信息,并继续处理工作区初始化。

用户只需要做两件事:

  • 提供邮箱地址
  • 把邮件里最新的 8 位验证码发给代理

这就是这套流程的核心价值。

一个链接就够了

发现接口会在同一个响应里返回服务说明、认证方式、第一步该做什么,以及后续步骤的指引。

所以你不需要再为每个工具单独写一份接入说明。把这个 URL 交给代理,让它按照返回结果继续往下执行就够了。

GET https://api.flashcards-open-source-app.com/v1/

代理拿到这个响应后,立刻就会知道四件事:

  • 这是 Flashcards 服务
  • 登录和注册都使用邮箱一次性验证码
  • 验证成功后会返回一个长期有效的 API 密钥
  • 登录之后要继续完成账户和工作区初始化

整个流程是什么样的

整个流程被刻意压缩得很短。

  1. 代理调用发现接口。
  2. 代理把用户邮箱发送到 send-code
  3. Flashcards 把 8 位验证码发到邮箱,并返回 otpSessionToken
  4. 代理向用户索取最新的验证码。
  5. 代理验证验证码,并拿到长期有效的 API 密钥。
  6. 代理调用 /v1/agent/me/v1/agent/workspaces
  7. 代理创建或选中正确的工作区,然后继续通过 /v1/agent/sql 工作。

这一点很重要,因为代理不会在“登录成功”后就停下来。它会继续完成后面的初始化步骤,并真正开始读写数据。

给 Claude Code 或 Codex 的示例提示词

下面这段提示词就够了:

Use this Flashcards discovery URL:
https://api.flashcards-open-source-app.com/v1/

Log in to my Flashcards account, load account context, and select or create the correct workspace.
Ask me only for the latest 8-digit email code when the flow requires it.

之后你就不需要再手动解释认证流程了,这个接口本身已经把步骤交代清楚。

给 OpenClaw 的示例提示词

思路完全一样,只是写得更明确一些:

Connect my Flashcards account using this URL:
https://api.flashcards-open-source-app.com/v1/

Follow the returned instructions, keep the API key secure, load my account, then continue to workspace setup.
If verification is needed, ask me for the latest 8-digit code from the email.

示例:发现响应

第一条请求如下:

curl https://api.flashcards-open-source-app.com/v1/

返回结果的结构就是为了让终端代理无需猜测,就能直接继续往下执行:

{
  "ok": true,
  "data": {
    "service": {
      "name": "flashcards-open-source-app",
      "version": "v1",
      "description": "Offline-first flashcards service with user-owned workspaces and a compact SQL agent surface."
    },
    "authentication": {
      "type": "email_otp_then_api_key",
      "sendCodeUrl": "https://auth.flashcards-open-source-app.com/api/agent/send-code",
      "verifyCodeUrl": "https://auth.flashcards-open-source-app.com/api/agent/verify-code"
    },
    "capabilitiesAfterLogin": [
      "Load account context",
      "Select a workspace",
      "Inspect runtime discovery and the published SQL surface through SQL introspection",
      "Read and write cards and decks through /agent/sql"
    ],
    "authBaseUrl": "https://auth.flashcards-open-source-app.com",
    "apiBaseUrl": "https://api.flashcards-open-source-app.com/v1",
    "surface": {
      "accountUrl": "https://api.flashcards-open-source-app.com/v1/agent/me",
      "workspacesUrl": "https://api.flashcards-open-source-app.com/v1/agent/workspaces",
      "sqlUrl": "https://api.flashcards-open-source-app.com/v1/agent/sql"
    }
  },
  "instructions": "Start with POST https://auth.flashcards-open-source-app.com/api/agent/send-code using the user's email, then POST https://auth.flashcards-open-source-app.com/api/agent/verify-code to obtain an API key. After login, call GET https://api.flashcards-open-source-app.com/v1/agent/me, then GET https://api.flashcards-open-source-app.com/v1/agent/workspaces?limit=100. If no workspace is selected for this API key, call POST https://api.flashcards-open-source-app.com/v1/agent/workspaces/{workspaceId}/select or create one with POST https://api.flashcards-open-source-app.com/v1/agent/workspaces using {\"name\":\"Personal\"}. After workspace bootstrap, use POST https://api.flashcards-open-source-app.com/v1/agent/sql for all shared card and deck reads and writes. Use docs.discoveryUrl for runtime discovery and docs.source.agentRoutesUrl for implementation details. The SQL surface is intentionally limited and is not full PostgreSQL.",
  "docs": {
    "discoveryUrl": "https://api.flashcards-open-source-app.com/v1/",
    "docsUrl": "https://flashcards-open-source-app.com/zh/docs/",
    "source": {
      "agentRoutesUrl": "https://github.com/kirill-markin/flashcards-open-source-app/tree/main/apps/backend/src/routes"
    }
  }
}

示例:发送邮件验证码

代理拿到用户邮箱之后,就会进入邮箱验证码这一步:

curl -X POST https://auth.flashcards-open-source-app.com/api/agent/send-code \
  -H "Content-Type: application/json" \
  -d '{
    "email": "you@example.com"
  }'

服务端会把邮件发出去,并返回一个短期有效的验证会话:

{
  "ok": true,
  "data": {
    "email": "you@example.com",
    "otpSessionToken": "...",
    "expiresInSeconds": 180,
    "authBaseUrl": "https://auth.flashcards-open-source-app.com",
    "apiBaseUrl": "https://api.flashcards-open-source-app.com/v1"
  },
  "instructions": "A verification code has been sent to the user's email. Ask for the 8-digit code from the email, then call verify_code with code, otpSessionToken, and a label for this agent connection. Read payload from data.* and do not expect resource fields at the top level. Select the next endpoint from instructions and confirm it with actions. Use docs.discoveryUrl for runtime routes and docs.source.authRoutesUrl for implementation details.",
  "docs": {
    "discoveryUrl": "https://api.flashcards-open-source-app.com/v1/",
    "source": {
      "authRoutesUrl": "https://github.com/kirill-markin/flashcards-open-source-app/tree/main/apps/auth/src/routes/agent"
    }
  }
}

这时候代理只需要短暂停一下,向用户要收件箱里最新的那组验证码。

示例:校验验证码并拿到 API 密钥

用户把邮件里的验证码发回来之后,代理就可以完成登录:

curl -X POST https://auth.flashcards-open-source-app.com/api/agent/verify-code \
  -H "Content-Type: application/json" \
  -d '{
    "code": "12345678",
    "otpSessionToken": "...",
    "label": "Claude Code on MacBook"
  }'

验证成功后,会返回一个长期有效的 API 密钥,以及下一步该做什么的指引:

{
  "ok": true,
  "data": {
    "apiKey": "fca_ABCDEFGH_0123456789ABCDEFGHJKMNPQRS",
    "authorizationScheme": "ApiKey",
    "apiBaseUrl": "https://api.flashcards-open-source-app.com/v1",
    "connection": {
      "connectionId": "connection-1",
      "label": "codex-import-bot",
      "createdAt": "2026-03-11T08:55:00.000Z",
      "lastUsedAt": null,
      "revokedAt": null
    }
  },
  "instructions": "Store this API key outside chat memory now. Use it in the Authorization header as 'ApiKey <key>'. Next call GET /v1/agent/me to load account context. Then call GET /v1/agent/workspaces?limit=100. If exactly one workspace exists, select it if needed. If no workspace exists, create one with POST /v1/agent/workspaces using {\"name\":\"Personal\"}. After a workspace is selected, use POST /v1/agent/sql for all data access. Use docs.discoveryUrl for runtime routes and docs.source.authRoutesUrl for implementation details.",
  "docs": {
    "discoveryUrl": "https://api.flashcards-open-source-app.com/v1/",
    "source": {
      "authRoutesUrl": "https://github.com/kirill-markin/flashcards-open-source-app/tree/main/apps/auth/src/routes/agent"
    }
  }
}

这就是代理从“处理认证”切换到“开始使用账户”的分界点。

拿到这个 API 密钥之后,应当立刻把它保存在聊天上下文之外。最干净的做法,是先把它导出为环境变量,之后让代理重复使用:

export FLASHCARDS_OPEN_SOURCE_API_KEY="fca_ABCDEFGH_0123456789ABCDEFGHJKMNPQRS"

示例:加载账户并继续进入工作区

下一条请求就是一次普通的带认证 API 调用:

curl https://api.flashcards-open-source-app.com/v1/agent/me \
  -H "Authorization: ApiKey YOUR_API_KEY"

返回结果会明确告诉代理,继续完成工作区初始化:

{
  "ok": true,
  "data": {
    "userId": "user-123",
    "selectedWorkspaceId": null,
    "authTransport": "api_key",
    "profile": {
      "email": "you@example.com",
      "locale": "en",
      "createdAt": "2026-03-10T12:00:00.000Z"
    }
  },
  "instructions": "Next call GET https://api.flashcards-open-source-app.com/v1/agent/workspaces?limit=100 to inspect available workspaces for this API key. If data.nextCursor is not null, continue with the same endpoint and cursor=data.nextCursor until it becomes null. If no workspace is selected, call POST https://api.flashcards-open-source-app.com/v1/agent/workspaces/{workspaceId}/select. If no workspace exists, create one with POST https://api.flashcards-open-source-app.com/v1/agent/workspaces using {\"name\":\"Personal\"}. After a workspace is selected, use POST https://api.flashcards-open-source-app.com/v1/agent/sql for reads, writes, and SQL introspection. Read payload from data.* and use docs.discoveryUrl for runtime routes and docs.source.agentRoutesUrl for implementation details.",
  "docs": {
    "discoveryUrl": "https://api.flashcards-open-source-app.com/v1/",
    "source": {
      "agentRoutesUrl": "https://github.com/kirill-markin/flashcards-open-source-app/tree/main/apps/backend/src/routes"
    }
  }
}

从这里开始,代理就可以:

  • 读取全部工作区
  • 如果还没有工作区,就创建第一个工作区
  • 如果有多个工作区,就选中正确的那个
  • 通过 /v1/ 的发现信息查看运行时路由
  • 通过 POST /v1/agent/sql 执行读取、写入和 SQL 自省

这样一来,这个登录流程就不只是“技术上可行”,而是真的能在实际使用中发挥价值。

OpenAPI 已不可用,/v1/ 是运行时发现入口。四个旧规范路径 /v1/openapi.json/v1/swagger.json/v1/agent/openapi.json/v1/agent/swagger.json 现在不会返回架构,而是返回同一份包含 openapiAvailable: false 的 JSON 发现通知。

为什么这比手动设置 API 密钥更好

传统的 API 接入方式依然很别扭:

  • 先在浏览器里登录
  • 再打开设置页
  • 手动创建令牌
  • 把它复制到另一个工具里
  • 还得一直开着文档,好让工具知道下一步做什么

而这套流程把其中大部分步骤都省掉了。

用户通过邮箱一次性验证码证明身份,服务端再把长期有效的 API 密钥直接交给代理。同一种响应格式还会持续告诉代理下一步该做什么。

这对用户更简单,也更容易自动化。

这是开源的

Flashcards 是开源项目,所以你可以直接检查整个流程,而不是把它当成黑盒来用。

如果你关心开源 API 认证、邮箱一次性验证码登录,或者代理接入流程的设计,这几份文件最值得读。

试试看

如果你想亲自试试这套流程,把这个 URL 交给你的代理:

https://api.flashcards-open-source-app.com/v1/

然后让它处理剩下的步骤。

有用的链接:

如果产品本身是开源的,认证流程又足够简洁,那么“让代理自己处理”这件事就应该真正可行。这正是这套流程存在的意义。

继续阅读