mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-06-24 10:17:35 -07:00
89 lines
2.9 KiB
TypeScript
89 lines
2.9 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2026 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import type { HttpHeaders } from '@a2a-js/sdk/client';
|
|
import { BaseA2AAuthProvider } from './base-provider.js';
|
|
import type { HttpAuthConfig } from './types.js';
|
|
import { resolveAuthValue } from './value-resolver.js';
|
|
import { debugLogger } from '../../utils/debugLogger.js';
|
|
|
|
/**
|
|
* Authentication provider for HTTP authentication schemes.
|
|
* Supports Bearer, Basic, and any IANA-registered scheme via raw value.
|
|
*/
|
|
export class HttpAuthProvider extends BaseA2AAuthProvider {
|
|
readonly type = 'http';
|
|
|
|
private resolvedToken?: string;
|
|
private resolvedUsername?: string;
|
|
private resolvedPassword?: string;
|
|
private resolvedValue?: string;
|
|
|
|
constructor(private readonly config: HttpAuthConfig) {
|
|
super();
|
|
}
|
|
|
|
override async initialize(): Promise<void> {
|
|
const config = this.config;
|
|
if ('token' in config) {
|
|
this.resolvedToken = await resolveAuthValue(config.token);
|
|
} else if ('username' in config) {
|
|
this.resolvedUsername = await resolveAuthValue(config.username);
|
|
this.resolvedPassword = await resolveAuthValue(config.password);
|
|
} else {
|
|
// Generic raw value for any other IANA-registered scheme
|
|
this.resolvedValue = await resolveAuthValue(config.value);
|
|
}
|
|
debugLogger.debug(
|
|
`[HttpAuthProvider] Initialized with scheme: ${this.config.scheme}`,
|
|
);
|
|
}
|
|
|
|
override async headers(): Promise<HttpHeaders> {
|
|
const config = this.config;
|
|
if ('token' in config) {
|
|
if (!this.resolvedToken)
|
|
throw new Error('HttpAuthProvider not initialized');
|
|
return { Authorization: `Bearer ${this.resolvedToken}` };
|
|
}
|
|
|
|
if ('username' in config) {
|
|
if (!this.resolvedUsername || !this.resolvedPassword) {
|
|
throw new Error('HttpAuthProvider not initialized');
|
|
}
|
|
const credentials = Buffer.from(
|
|
`${this.resolvedUsername}:${this.resolvedPassword}`,
|
|
).toString('base64');
|
|
return { Authorization: `Basic ${credentials}` };
|
|
}
|
|
|
|
// Generic raw value for any other IANA-registered scheme
|
|
if (!this.resolvedValue)
|
|
throw new Error('HttpAuthProvider not initialized');
|
|
return { Authorization: `${config.scheme} ${this.resolvedValue}` };
|
|
}
|
|
|
|
/**
|
|
* Re-resolves credentials on auth failure (e.g. rotated tokens via $ENV or !command).
|
|
* Respects MAX_AUTH_RETRIES from the base class to prevent infinite loops.
|
|
*/
|
|
override async shouldRetryWithHeaders(
|
|
req: RequestInit,
|
|
res: Response,
|
|
): Promise<HttpHeaders | undefined> {
|
|
if (res.status === 401 || res.status === 403) {
|
|
if (this.authRetryCount >= BaseA2AAuthProvider.MAX_AUTH_RETRIES) {
|
|
return undefined;
|
|
}
|
|
debugLogger.debug(
|
|
'[HttpAuthProvider] Re-resolving values after auth failure',
|
|
);
|
|
await this.initialize();
|
|
}
|
|
return super.shouldRetryWithHeaders(req, res);
|
|
}
|
|
}
|