// -----------------------------------------------------------------------------
// IOidcTokenProvider.cs
// Sprint: SPRINT_20251226_001_SIGNER_fulcio_keyless_client
// Task: 0012 - Add OIDC token acquisition from Authority
// Description: Interface for obtaining OIDC tokens for Fulcio authentication
// -----------------------------------------------------------------------------
namespace StellaOps.Signer.Keyless;
///
/// Provides OIDC identity tokens for Fulcio authentication.
///
public interface IOidcTokenProvider
{
///
/// Gets the OIDC issuer URL.
///
string Issuer { get; }
///
/// Acquires an OIDC identity token.
///
/// Cancellation token.
/// The OIDC token result containing the identity token.
Task AcquireTokenAsync(CancellationToken cancellationToken = default);
///
/// Gets a cached token if available and not expired.
///
/// The cached token, or null if not available or expired.
OidcTokenResult? GetCachedToken();
///
/// Clears any cached tokens.
///
void ClearCache();
}
///
/// Result of OIDC token acquisition.
///
public sealed record OidcTokenResult
{
///
/// The identity token (JWT).
///
public required string IdentityToken { get; init; }
///
/// When the token expires.
///
public required DateTimeOffset ExpiresAt { get; init; }
///
/// The subject claim from the token.
///
public string? Subject { get; init; }
///
/// The email claim from the token, if present.
///
public string? Email { get; init; }
///
/// Whether the token is expired.
///
public bool IsExpired => DateTimeOffset.UtcNow >= ExpiresAt;
///
/// Whether the token will expire within the specified buffer time.
///
public bool WillExpireSoon(TimeSpan buffer) =>
DateTimeOffset.UtcNow.Add(buffer) >= ExpiresAt;
}
///
/// Configuration for client credentials OIDC flow.
///
public sealed record OidcClientCredentialsConfig
{
///
/// The OIDC issuer URL.
///
public required string Issuer { get; init; }
///
/// The client ID.
///
public required string ClientId { get; init; }
///
/// The client secret.
///
public required string ClientSecret { get; init; }
///
/// Additional scopes to request.
///
public IReadOnlyList Scopes { get; init; } = ["openid", "email"];
///
/// Token endpoint URL (if different from discovery).
///
public string? TokenEndpoint { get; init; }
}
///
/// Configuration for ambient token OIDC (CI runner tokens, workload identity).
///
public sealed record OidcAmbientConfig
{
///
/// The OIDC issuer URL.
///
public required string Issuer { get; init; }
///
/// Path to the ambient token file.
///
public required string TokenPath { get; init; }
///
/// Whether to watch the token file for changes.
///
public bool WatchForChanges { get; init; } = true;
}