























@@ -1,3 +1,7 @@
1+/**
2+ * Implements Chutes OAuth PKCE, callback parsing, token exchange, and refresh
3+ * for agent model authentication.
4+ */
15import { createHash, randomBytes } from "node:crypto";
26import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
37import { resolveExpiresAtMsFromDurationSeconds } from "../infra/parse-finite-number.js";
@@ -18,6 +22,7 @@ type ChutesUserInfo = {
1822created_at?: string;
1923};
202425+/** OAuth client settings for the Chutes authorization-code flow. */
2126export type ChutesOAuthAppConfig = {
2227clientId: string;
2328clientSecret?: string;
@@ -29,12 +34,14 @@ type ChutesStoredOAuth = OAuthCredentials & {
2934clientId?: string;
3035};
313637+/** Generates a PKCE verifier/challenge pair for Chutes login. */
3238export function generateChutesPkce(): ChutesPkce {
3339const verifier = randomBytes(32).toString("hex");
3440const challenge = createHash("sha256").update(verifier).digest("base64url");
3541return { verifier, challenge };
3642}
374344+/** Parses pasted Chutes redirect input and enforces the expected OAuth state. */
3845export function parseOAuthCallbackInput(
3946input: string,
4047expectedState: string,
@@ -109,6 +116,7 @@ async function fetchChutesUserInfo(params: {
109116return typed;
110117}
111118119+/** Exchanges an authorization code for stored Chutes OAuth credentials. */
112120export async function exchangeChutesCodeForTokens(params: {
113121app: ChutesOAuthAppConfig;
114122code: string;
@@ -172,6 +180,7 @@ export async function exchangeChutesCodeForTokens(params: {
172180} as unknown as ChutesStoredOAuth;
173181}
174182183+/** Refreshes stored Chutes OAuth credentials, preserving refresh tokens when absent. */
175184export async function refreshChutesTokens(params: {
176185credential: ChutesStoredOAuth;
177186fetchFn?: typeof fetch;
@@ -229,7 +238,8 @@ export async function refreshChutesTokens(params: {
229238return {
230239 ...params.credential,
231240 access,
232-// RFC 6749 section 6: new refresh token is optional; if present, replace old.
241+// RFC 6749 section 6 makes new refresh tokens optional; Chutes may omit one
242+// on refresh, so preserve the old token unless a replacement is returned.
233243refresh: newRefresh || refreshToken,
234244 expires,
235245 clientId,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。