@anthropic-ai/sdk
Version:
The official TypeScript library for the Anthropic API
130 lines • 6.25 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.userOAuthProvider = userOAuthProvider;
const credentials_1 = require("../../core/credentials.js");
const types_1 = require("./types.js");
const time_1 = require("../../internal/utils/time.js");
const version_1 = require("../../version.js");
/**
* Reads a user-oauth credential file. Returns the cached access token while
* fresh; on expiry performs a `refresh_token` grant and writes the new
* tokens back to the credentials file (atomic replace, fsync'd).
*
* If `clientId` is empty, the access token is treated as static — the
* credentials file is read on every call but no refresh is attempted, and
* an expired token without a `refresh_token` raises.
*/
function userOAuthProvider(config) {
return async (opts) => {
const fs = await Promise.resolve().then(() => __importStar(require('node:fs')));
await (0, types_1.checkCredentialsFileSafety)(config.credentialsPath, config.onSafetyWarning);
let raw;
try {
raw = await fs.promises.readFile(config.credentialsPath, 'utf-8');
}
catch (err) {
throw new types_1.WorkloadIdentityError(`Credentials file not found at ${config.credentialsPath}: ${err}`);
}
let creds;
try {
creds = JSON.parse(raw);
}
catch (err) {
throw new types_1.WorkloadIdentityError(`Credentials file at ${config.credentialsPath} is not valid JSON: ${err}`);
}
const accessToken = creds.access_token;
if (!accessToken) {
throw new types_1.WorkloadIdentityError(`Credentials file at ${config.credentialsPath} must include 'access_token'`);
}
// Return cached token if still fresh (or no expiry info), unless the
// caller is forcing a refresh after a 401 — then go straight to refresh
// even if the file's expires_at still looks valid.
const expiresAt = creds.expires_at;
if (!opts?.forceRefresh &&
(expiresAt == null || (0, time_1.nowAsSeconds)() < expiresAt - types_1.MANDATORY_REFRESH_THRESHOLD_IN_SECONDS)) {
return { token: accessToken, expiresAt: expiresAt ?? null };
}
const refreshToken = creds.refresh_token;
if (!config.clientId || !refreshToken) {
throw new types_1.WorkloadIdentityError(`Access token at ${config.credentialsPath} has expired and no refresh is available ` +
`(client_id ${config.clientId ? 'set' : 'empty'}, refresh_token ${refreshToken ? 'set' : 'empty'})`);
}
(0, types_1.requireSecureTokenEndpoint)(config.baseURL);
const body = {
grant_type: types_1.GRANT_TYPE_REFRESH_TOKEN,
refresh_token: refreshToken,
client_id: config.clientId,
};
const url = `${config.baseURL}${types_1.TOKEN_ENDPOINT}`;
let resp;
try {
resp = await config.fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'anthropic-beta': types_1.OAUTH_API_BETA_HEADER,
'User-Agent': config.userAgent || `anthropic-sdk-typescript/${version_1.VERSION} userOAuthProvider`,
},
body: JSON.stringify(body),
});
}
catch (err) {
throw new types_1.WorkloadIdentityError(`User OAuth refresh failed to reach token endpoint: ${err}`);
}
const requestId = resp.headers.get('Request-Id');
if (!resp.ok) {
const text = await resp.text().catch(() => '');
throw new types_1.WorkloadIdentityError(`User OAuth refresh failed (HTTP ${resp.status}): ${(0, types_1.redactSensitive)(text)}`, resp.status, (0, types_1.redactSensitive)(text), requestId);
}
const data = await (0, types_1.parseTokenResponse)(resp, requestId);
const expiresIn = Number(data.expires_in);
if (!Number.isFinite(expiresIn)) {
throw new types_1.WorkloadIdentityError(`User OAuth refresh response missing or invalid expires_in: ${JSON.stringify((0, types_1.redactSensitive)(data))}`, resp.status, (0, types_1.redactSensitive)(data), requestId);
}
const newExpiresAt = (0, time_1.nowAsSeconds)() + expiresIn;
const newRefreshToken = data.refresh_token || refreshToken;
await (0, types_1.writeCredentialsFileAtomic)(config.credentialsPath, {
...creds,
version: credentials_1.CREDENTIALS_FILE_VERSION,
type: 'oauth_token',
access_token: data.access_token,
expires_at: newExpiresAt,
refresh_token: newRefreshToken,
});
return { token: data.access_token, expiresAt: newExpiresAt };
};
}
//# sourceMappingURL=user-oauth.js.map