canonical_id: "auth_oauth2" display_name: "Auth Primitive — OAuth2" category: "auth" version: "v1" wasi_target: "preview1" stability: "floating" runtime_compat: - "cf-workers" - "workerd" - "wazero" constraints: max_size_kb: 2048 max_cold_start_ms: 200 no_network_syscall: false no_filesystem_syscall: true io_model: "stdin_stdout_json" input_schema: type: object required: [action, api_key, service] properties: action: type: string enum: [authenticate, needs_refresh, refresh] description: | authenticate — 用 refresh_token 換 access_token,展開 inject 模板 needs_refresh — 檢查 token 是否需要 refresh(expires_at < now+300s) refresh — 強制重新 refresh,更新 CREDENTIALS_KV 中的 access_token/expires_at api_key: type: string description: 租戶識別(ak_ 前綴),用來組 {api_key}:cred:{name} KV key service: type: string description: auth recipe 名稱,對應 auth_recipe:{service} 的 KV 記錄 request: type: object description: 下游零件的 HTTP request 上下文(保留,auth_oauth2 當前不使用) output_schema: type: object properties: success: type: boolean needs_refresh: type: boolean description: action=needs_refresh 時有效 auth_headers: type: object additionalProperties: type: string auth_query: type: object additionalProperties: type: string auth_body: type: object additionalProperties: type: string runtime: type: object description: 含 access_token(action=authenticate/refresh 時有效) gherkin_tests: - scenario: "缺少 api_key" given: '{"action":"authenticate","service":"google"}' then_contains: '{"success":false' - scenario: "找不到 auth recipe" given: '{"action":"authenticate","api_key":"ak_test","service":"nonexistent_oauth2_svc"}' then_contains: '{"success":false' - scenario: "needs_refresh 無 expires_at" given: '{"action":"needs_refresh","api_key":"ak_test","service":"google"}' then_contains: '"needs_refresh":true' tags: [auth, credential, primitive, oauth2] description: | OAuth2 auth primitive。讀取 auth_recipe(含 token_endpoint、client_id、client_secret) + 解密 refresh_token + 呼叫 token endpoint 換 access_token + 展開 {{runtime.access_token}}。 支援 authenticate / needs_refresh / refresh 三個 action。 透過 host function kv_get + crypto_decrypt + http_request,plaintext 永不離開 WASM。 config_example: | auth_step: component: "auth_oauth2" action: "authenticate" service: "google_drive" # 對應 auth_recipe:google_drive 的 KV 記錄