authentication
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAuthentication
认证
Overview
概述
Spuree is an agent-friendly cloud storage. Projects contain folders (nestable) and files at any level. Authenticate with a JWT token or API key to access all V1 endpoints.
Tokens follow OAuth2 conventions and are issued as NextAuth-compatible JWTs.
Use this skill when an agent needs to:
- Set up API access for the first time
- Log in with email and password to get an access token
- Refresh an expired access token using a refresh token
- Exchange an authorization code for tokens (browser SSO flow)
- Create, list, or revoke API keys
Spuree是一款对Agent友好的云存储服务。项目包含可嵌套的文件夹和任意层级的文件。通过JWT令牌或API密钥进行认证,即可访问所有V1端点。
令牌遵循OAuth2规范,以兼容NextAuth的JWT格式颁发。
当Agent需要执行以下操作时,可使用本技能:
- 首次设置API访问权限
- 使用邮箱和密码登录以获取访问令牌
- 使用刷新令牌刷新过期的访问令牌
- 交换授权码以获取令牌(浏览器SSO流程)
- 创建、列出或撤销API密钥
Getting Started
快速开始
First-time setup — three options:
首次设置有三种可选方式:
Option A: User creates API key from web UI
选项A:用户通过Web UI创建API密钥
- Create a Spuree account at studio.spuree.com
- Go to studio.spuree.com/api-keys and create a key. Save it immediately — the key is only shown once.
- Set the environment variable:
bash
export SPUREE_API_KEY="<your-api-key>"
- 在studio.spuree.com创建Spuree账户
- 前往studio.spuree.com/api-keys创建密钥。请立即保存——密钥仅会显示一次。
- 设置环境变量:
bash
export SPUREE_API_KEY="<your-api-key>"
Option B: Agent logs in with email and password
选项B:Agent使用邮箱和密码登录
If the user provides their email and password, the agent can set up its own API key:
- Log in with to get a temporary JWT
POST /auth/token - Create an API key with
POST /v1/api-keys - Store the key in
$SPUREE_API_KEY
如果用户提供邮箱和密码,Agent可自行设置API密钥:
- 通过登录以获取临时JWT
POST /auth/token - 通过创建API密钥
POST /v1/api-keys - 将密钥存储在中
$SPUREE_API_KEY
Option C: Agent opens browser for SSO login
选项C:Agent打开浏览器进行SSO登录
The agent can authenticate without the user sharing their password:
- Start a local HTTP server on an ephemeral port (49152–65535) to receive the callback.
- Open the user's browser to the Spuree sign-in page with and the port:
source=apiThe user logs in via Google SSO (or email/password) in the browser.https://studio.spuree.com/auth/signin?source=api&port=<port> - After login, Spuree redirects to . The agent receives the exchange code from this callback (valid for 60 seconds).
http://localhost:<port>/callback?token=<exchange-code> - Exchange the code for a JWT:
bash
curl -X POST "https://studio.spuree.com/api/auth/token/exchange" \ -H "Content-Type: application/json" \ -d '{"code": "<exchange-code>"}' - Create an API key with the JWT () and store it in
POST /v1/api-keys.$SPUREE_API_KEY
Once is set, the agent authenticates with on all requests. No login or token refresh needed.
$SPUREE_API_KEYX-API-Key: $SPUREE_API_KEYVerify it works — ask your agent:
"List my Spuree projects"
The agent should show you which projects you have access to. If it works, your API key is set up correctly.
Try it out — ask your agent something like:
"Upload this file to my Spuree project"
Agent无需用户共享密码即可完成认证:
- 在临时端口(49152–65535)启动本地HTTP服务器以接收回调。
- 打开用户浏览器访问Spuree登录页面,携带和端口参数:
source=api用户在浏览器中通过Google SSO(或邮箱/密码)完成登录。https://studio.spuree.com/auth/signin?source=api&port=<port> - 登录完成后,Spuree会重定向至。Agent从该回调中获取交换码(有效期60秒)。
http://localhost:<port>/callback?token=<exchange-code> - 交换码换取JWT:
bash
curl -X POST "https://studio.spuree.com/api/auth/token/exchange" \ -H "Content-Type: application/json" \ -d '{"code": "<exchange-code>"}' - 使用JWT创建API密钥()并存储在
POST /v1/api-keys中。$SPUREE_API_KEY
设置好后,Agent在所有请求中使用进行认证,无需登录或刷新令牌。
$SPUREE_API_KEYX-API-Key: $SPUREE_API_KEY验证是否生效——向你的Agent询问:
"列出我的Spuree项目"
Agent应展示你有权访问的项目。如果正常返回,说明你的API密钥设置正确。
尝试使用——向你的Agent发送类似请求:
"将此文件上传至我的Spuree项目"
Base URLs
基础URL
Spuree uses two hosts:
| Host | Purpose | Endpoints |
|---|---|---|
| Authentication (login, refresh, exchange) | |
| All V1 data APIs (projects, files, etc.) | |
All other skills in this repo use . Only the token endpoints below use .
https://data.spuree.com/apistudio.spuree.comSpuree使用两个主机地址:
| 主机地址 | 用途 | 端点 |
|---|---|---|
| 认证(登录、刷新、交换) | |
| 所有V1数据API(项目、文件等) | |
本仓库中的所有其他技能均使用。仅以下令牌端点使用。
https://data.spuree.com/apistudio.spuree.comToken Lifecycle
令牌生命周期
| Token | Lifetime | Format |
|---|---|---|
| 1 hour | NextAuth JWT |
| 30 days | Opaque hex string |
| 60 seconds | Opaque string |
The is what you pass as to V1 API endpoints.
access_tokenAuthorization: Bearer <access_token>Alternatively, you can create API keys for long-lived, non-interactive access. API keys are passed via header and can be scoped to specific organizations.
X-API-Key| 令牌 | 有效期 | 格式 |
|---|---|---|
| 1小时 | NextAuth JWT |
| 30天 | 不透明十六进制字符串 |
| 60秒 | 不透明字符串 |
access_tokenAuthorization: Bearer <access_token>另外,你可以创建API密钥以实现长期、非交互式访问。API密钥通过头传递,可限定在特定组织范围内。
X-API-KeyToken Response Format
令牌响应格式
All three endpoints return the same OAuth2-compliant response:
json
{
"access_token": "eyJhbGciOiJkaXIiLCJlbmMiOi...",
"refresh_token": "a1b2c3d4e5f6...",
"expires_in": 3600,
"user": {
"id": "64a7b8c9d1e2f3a4b5c6d7e8",
"email": "user@example.com",
"name": "User Name",
"image": "https://...",
"organizationId": "64a7b8c9d1e2f3a4b5c6d7f0",
"role": "admin",
"workspaces": [
{
"workspaceId": "64a7b8c9d1e2f3a4b5c6d7f1",
"workspaceName": "My Workspace",
"role": "owner"
}
]
}
}三个端点均返回符合OAuth2规范的响应:
json
{
"access_token": "eyJhbGciOiJkaXIiLCJlbmMiOi...",
"refresh_token": "a1b2c3d4e5f6...",
"expires_in": 3600,
"user": {
"id": "64a7b8c9d1e2f3a4b5c6d7e8",
"email": "user@example.com",
"name": "User Name",
"image": "https://...",
"organizationId": "64a7b8c9d1e2f3a4b5c6d7f0",
"role": "admin",
"workspaces": [
{
"workspaceId": "64a7b8c9d1e2f3a4b5c6d7f1",
"workspaceName": "My Workspace",
"role": "owner"
}
]
}
}Endpoints
端点
POST /auth/token
POST /auth/token
Log in with email and password.
Description: Validates credentials and returns an access token and refresh token. Rate limited to 10 requests per minute per IP.
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
| string | Yes | User's email address |
| string | Yes | User's password |
Status Codes:
| Code | Description |
|---|---|
| 200 | Login successful, tokens returned |
| 400 | Invalid request body or missing fields |
| 401 | Invalid email or password, or account locked |
| 429 | Rate limit exceeded (10 req/min) |
| 500 | Internal server error |
Error Messages (401):
| Message | Cause |
|---|---|
| Wrong credentials |
| User registered via OAuth only |
| Too many failed attempts (5 failures → 15 min lock) |
Example:
bash
curl -X POST "https://studio.spuree.com/api/auth/token" \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "mypassword"
}'使用邮箱和密码登录。
**描述:**验证凭据并返回访问令牌和刷新令牌。每个IP每分钟最多允许10次请求。
请求体:
| 字段 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
| string | 是 | 用户邮箱地址 |
| string | 是 | 用户密码 |
状态码:
| 状态码 | 描述 |
|---|---|
| 200 | 登录成功,返回令牌 |
| 400 | 请求体无效或字段缺失 |
| 401 | 邮箱或密码无效,或账户被锁定 |
| 429 | 请求超出速率限制(10次/分钟) |
| 500 | 内部服务器错误 |
错误信息(401):
| 信息 | 原因 |
|---|---|
| 凭据错误 |
| 用户仅通过OAuth注册 |
| 失败尝试过多(5次失败→锁定15分钟) |
示例:
bash
curl -X POST "https://studio.spuree.com/api/auth/token" \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "mypassword"
}'POST /auth/token/refresh
POST /auth/token/refresh
Refresh an expired access token.
Description: Exchanges a valid refresh token for a new access token and refresh token pair. The old refresh token is atomically revoked to prevent reuse. Rate limited to 10 requests per minute per IP.
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
| string | Yes | The refresh token from a previous login or refresh |
Status Codes:
| Code | Description |
|---|---|
| 200 | New tokens issued |
| 400 | Missing refresh token |
| 401 | Invalid or expired refresh token |
| 429 | Rate limit exceeded |
| 500 | Internal server error |
Example:
bash
curl -X POST "https://studio.spuree.com/api/auth/token/refresh" \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "a1b2c3d4e5f6..."
}'Notes:
- Each refresh token can only be used once. After refresh, use the new for subsequent refreshes.
refresh_token - If a refresh token is reused (already revoked), it returns 401.
刷新过期的访问令牌。
**描述:**使用有效的刷新令牌换取新的访问令牌和刷新令牌对。旧的刷新令牌会被自动撤销以防止重复使用。每个IP每分钟最多允许10次请求。
请求体:
| 字段 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
| string | 是 | 之前登录或刷新获取的刷新令牌 |
状态码:
| 状态码 | 描述 |
|---|---|
| 200 | 颁发新令牌 |
| 400 | 缺少刷新令牌 |
| 401 | 刷新令牌无效或过期 |
| 429 | 请求超出速率限制 |
| 500 | 内部服务器错误 |
示例:
bash
curl -X POST "https://studio.spuree.com/api/auth/token/refresh" \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "a1b2c3d4e5f6..."
}'注意:
- 每个刷新令牌仅能使用一次。刷新后,后续刷新需使用新的。
refresh_token - 如果刷新令牌被重复使用(已撤销),会返回401。
POST /auth/token/exchange
POST /auth/token/exchange
Exchange an authorization code for tokens.
Description: Exchanges a one-time authorization code for an access token and refresh token. Used by agents and desktop apps that authenticate via the browser (see Getting Started Option C). The login flow starts at — after the user completes login, the exchange code is delivered to the agent's local callback server. Rate limited to 10 requests per minute per IP.
studio.spuree.com/auth/signin?source=apiRequest Body:
| Field | Type | Required | Description |
|---|---|---|---|
| string | Yes | The authorization exchange code |
Status Codes:
| Code | Description |
|---|---|
| 200 | Tokens issued |
| 400 | Missing exchange code |
| 401 | Invalid or expired exchange code |
| 429 | Rate limit exceeded |
| 500 | Internal server error |
Example:
bash
curl -X POST "https://studio.spuree.com/api/auth/token/exchange" \
-H "Content-Type: application/json" \
-d '{
"code": "exchange-code-here"
}'Notes:
- Exchange codes expire after 60 seconds.
- Each code can only be used once.
交换授权码以获取令牌。
**描述:**使用一次性授权码换取访问令牌和刷新令牌。供Agent和桌面应用通过浏览器认证使用(见快速开始选项C)。登录流程从开始——用户完成登录后,交换码会发送至Agent的本地回调服务器。每个IP每分钟最多允许10次请求。
studio.spuree.com/auth/signin?source=api请求体:
| 字段 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
| string | 是 | 授权交换码 |
状态码:
| 状态码 | 描述 |
|---|---|
| 200 | 颁发令牌 |
| 400 | 缺少交换码 |
| 401 | 交换码无效或过期 |
| 429 | 请求超出速率限制 |
| 500 | 内部服务器错误 |
示例:
bash
curl -X POST "https://studio.spuree.com/api/auth/token/exchange" \
-H "Content-Type: application/json" \
-d '{
"code": "exchange-code-here"
}'注意:
- 交换码有效期为60秒。
- 每个交换码仅能使用一次。
API Keys
API密钥
API keys provide long-lived authentication for automated workflows. They are scoped to a user and optionally restricted to specific organizations.
All V1 endpoints accept either or . When both are provided, JWT takes priority.
Authorization: Bearer <jwt>X-API-Key: <api-key>API密钥为自动化工作流提供长期认证。它们与用户绑定,可选择性限定在特定组织范围内。
所有V1端点均接受或。当两者同时提供时,JWT优先级更高。
Authorization: Bearer <jwt>X-API-Key: <api-key>POST /v1/api-keys
POST /v1/api-keys
Create a new API key.
Auth: Requires JWT (Bearer token only, not API key).
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
| string | Yes | Descriptive name for the key |
| object | No | |
| datetime | No | Expiration timestamp (ISO 8601). Omit for no expiry. |
Response:
json
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "CI Pipeline Key",
"key": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
"createdAt": "2024-01-15T10:00:00Z",
"expiresAt": null,
"lastUsedAt": null,
"scopes": { "organizations": ["64a7b8c9d1e2f3a4b5c6d7f0"] },
"status": "active"
}Important: Thefield is only returned once at creation. Store it securely.key
Example:
bash
curl -X POST "https://data.spuree.com/api/v1/api-keys" \
-H "Authorization: Bearer $SPUREE_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "CI Pipeline Key",
"scopes": { "organizations": ["64a7b8c9d1e2f3a4b5c6d7f0"] }
}'创建新的API密钥。
**认证:**需要JWT(仅支持Bearer令牌,不支持API密钥)。
请求体:
| 字段 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
| string | 是 | 密钥的描述性名称 |
| object | 否 | |
| datetime | 否 | 过期时间戳(ISO 8601格式)。省略则永不过期。 |
响应:
json
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "CI Pipeline Key",
"key": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
"createdAt": "2024-01-15T10:00:00Z",
"expiresAt": null,
"lastUsedAt": null,
"scopes": { "organizations": ["64a7b8c9d1e2f3a4b5c6d7f0"] },
"status": "active"
}重要提示:字段仅在创建时返回一次。请安全存储。key
示例:
bash
curl -X POST "https://data.spuree.com/api/v1/api-keys" \
-H "Authorization: Bearer $SPUREE_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "CI Pipeline Key",
"scopes": { "organizations": ["64a7b8c9d1e2f3a4b5c6d7f0"] }
}'GET /v1/api-keys
GET /v1/api-keys
List all active API keys for the authenticated user.
Auth: Requires JWT (Bearer token only).
Response:
json
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "CI Pipeline Key",
"createdAt": "2024-01-15T10:00:00Z",
"expiresAt": null,
"lastUsedAt": "2024-03-10T14:30:00Z",
"scopes": { "organizations": ["64a7b8c9d1e2f3a4b5c6d7f0"] },
"status": "active"
}
]Example:
bash
curl "https://data.spuree.com/api/v1/api-keys" \
-H "Authorization: Bearer $SPUREE_ACCESS_TOKEN"列出已认证用户的所有活跃API密钥。
**认证:**需要JWT(仅支持Bearer令牌)。
响应:
json
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "CI Pipeline Key",
"createdAt": "2024-01-15T10:00:00Z",
"expiresAt": null,
"lastUsedAt": "2024-03-10T14:30:00Z",
"scopes": { "organizations": ["64a7b8c9d1e2f3a4b5c6d7f0"] },
"status": "active"
}
]示例:
bash
curl "https://data.spuree.com/api/v1/api-keys" \
-H "Authorization: Bearer $SPUREE_ACCESS_TOKEN"DELETE /v1/api-keys/{key_id}
DELETE /v1/api-keys/{key_id}
Revoke an API key (soft delete).
Auth: Requires JWT (Bearer token only).
Response:
json
{ "success": true }Example:
bash
curl -X DELETE "https://data.spuree.com/api/v1/api-keys/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer $SPUREE_ACCESS_TOKEN"撤销API密钥(软删除)。
**认证:**需要JWT(仅支持Bearer令牌)。
响应:
json
{ "success": true }示例:
bash
curl -X DELETE "https://data.spuree.com/api/v1/api-keys/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer $SPUREE_ACCESS_TOKEN"Token Storage
令牌存储
Store tokens in environment variables using these standard names:
SPUREE_ACCESS_TOKEN=eyJhbGci... # JWT access token (1 hour)
SPUREE_REFRESH_TOKEN=a1b2c3d4... # For refreshing access token (30 days)
SPUREE_API_KEY=a1b2c3d4... # API key (64-char hex, long-lived)All Spuree skills reference these variable names. V1 endpoints accept either or .
Authorization: Bearer $SPUREE_ACCESS_TOKENX-API-Key: $SPUREE_API_KEY使用以下标准名称将令牌存储在环境变量中:
SPUREE_ACCESS_TOKEN=eyJhbGci... # JWT访问令牌(有效期1小时)
SPUREE_REFRESH_TOKEN=a1b2c3d4... # 用于刷新访问令牌(有效期30天)
SPUREE_API_KEY=a1b2c3d4... # API密钥(64位十六进制,长期有效)所有Spuree技能均引用这些变量名称。V1端点接受或。
Authorization: Bearer $SPUREE_ACCESS_TOKENX-API-Key: $SPUREE_API_KEYCommon Patterns
常见模式
Agent Login Flow
Agent登录流程
-
Obtain tokens with email and password:
POST /auth/token → { access_token, refresh_token, expires_in, user } -
Use access token for V1 API calls:
Authorization: Bearer {access_token} -
Refresh before the token expires (every ~55 minutes):
POST /auth/token/refresh → { access_token, refresh_token, ... }
-
获取令牌:使用邮箱和密码登录:
POST /auth/token → { access_token, refresh_token, expires_in, user } -
使用访问令牌:调用V1 API:
Authorization: Bearer {access_token} -
刷新令牌:在令牌过期前刷新(约每55分钟一次):
POST /auth/token/refresh → { access_token, refresh_token, ... }
Token Refresh Strategy
令牌刷新策略
- is
expires_in(1 hour). Refresh proactively at ~55 minutes to avoid failed requests.3600 - Always store and use the latest — old ones are revoked after use.
refresh_token - If refresh fails with 401, the user must log in again with email/password.
- 为
expires_in(1小时)。建议提前约55分钟刷新令牌,避免请求失败。3600 - 始终存储并使用最新的——旧令牌在使用后会被撤销。
refresh_token - 如果刷新请求返回401失败,用户需重新使用邮箱/密码登录。
API Key for Automation
自动化场景使用API密钥
For CI/CD pipelines or long-running agents that can't refresh tokens:
- Log in to get a JWT
- Create an API key scoped to the needed organizations:
POST /v1/api-keys → { key: "a1b2c3d4..." } - Use the API key for all subsequent requests:
X-API-Key: a1b2c3d4...
API keys don't expire by default (unless is set) and don't need refreshing.
expiresAt对于CI/CD流水线或无法刷新令牌的长期运行Agent:
- 登录获取JWT
- 创建API密钥并限定在所需组织范围内:
POST /v1/api-keys → { key: "a1b2c3d4..." } - 使用API密钥进行所有后续请求:
X-API-Key: a1b2c3d4...
API密钥默认永不过期(除非设置了),无需刷新。
expiresAtError Handling
错误处理
| Error | Cause | Resolution |
|---|---|---|
| 401 (invalid credentials) | Wrong email or password | Verify credentials |
| 401 (account locked) | 5 failed login attempts | Wait 15 minutes, then retry |
| 401 (invalid refresh token) | Token expired, revoked, or reused | Log in again with email/password |
| 401 (invalid exchange code) | Code expired or already used | Request a new exchange code |
| 429 (rate limit) | More than 10 requests/min from same IP | Wait and retry with backoff |
| 错误 | 原因 | 解决方法 |
|---|---|---|
| 401(凭据无效) | 邮箱或密码错误 | 验证凭据正确性 |
| 401(账户锁定) | 5次登录失败尝试 | 等待15分钟后重试 |
| 401(刷新令牌无效) | 令牌过期、已撤销或重复使用 | 使用邮箱/密码重新登录 |
| 401(交换码无效) | 交换码过期或已使用 | 请求新的交换码 |
| 429(速率限制) | 同一IP每分钟请求超过10次 | 等待后重试,实现指数退避 |
Rate Limits
速率限制
All authentication endpoints share the same rate limit: 10 requests per minute per IP. Implement exponential backoff when receiving 429 responses.
所有认证端点共享相同的速率限制:每个IP每分钟最多10次请求。收到429响应时,请实现指数退避策略。