The default transport for IAltchaVerifier / IAltchaChallengeProvider —
calls a self-hosted altcha service over gRPC.
Wire contract
- Protos/altcha.proto defines svrnty.cqrs.altcha.v1.AltchaService with
CreateChallenge + VerifyChallenge RPCs. Shipped in this package as
source-of-truth; Go (and other) implementations vendor a copy.
- Challenge.challenge_hash is named (not "challenge") to avoid a C#
property/class name collision; the MinimalApi widget JSON remaps.
Runtime
- AltchaGrpcVerifier maps RpcException → AltchaVerifyResult.Fail with
a diagnostic reason ("verify-timeout", "service-unavailable", etc.)
so the auth check surfaces a clean Unauthorized without leaking
transport detail.
- AltchaGrpcChallengeProvider lets create-challenge failures bubble
(challenge endpoint should 5xx if altcha is down — clients retry).
- AltchaGrpcOptions.TokenProvider hook for consumer-supplied HMAC
service-token minting (plan-b will plug in ServiceTokenIssuer).
- AddGrpcClient<AltchaServiceClient> registered with HttpClientFactory.
AddSvrntyAltchaGrpcVerifier(Action<...>) and overload binding from
IConfiguration cover both wiring styles.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
65 lines
2.3 KiB
C#
65 lines
2.3 KiB
C#
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
|
using Svrnty.CQRS.Altcha.Abstractions;
|
|
|
|
namespace Svrnty.CQRS.Altcha.Grpc;
|
|
|
|
public static class ServiceCollectionExtensions
|
|
{
|
|
/// <summary>
|
|
/// Registers the gRPC-backed <see cref="IAltchaVerifier"/> and
|
|
/// <see cref="IAltchaChallengeProvider"/>. Configure the endpoint
|
|
/// and optional service-auth token provider via the
|
|
/// <paramref name="configure"/> delegate.
|
|
/// </summary>
|
|
/// <example>
|
|
/// <code>
|
|
/// services.AddSvrntyAltcha();
|
|
/// services.AddSvrntyAltchaGrpcVerifier(opts =>
|
|
/// {
|
|
/// opts.Endpoint = "http://altcha:9090";
|
|
/// opts.TokenProvider = async ct => await tokenIssuer.GetTokenAsync("altcha", ct);
|
|
/// });
|
|
/// </code>
|
|
/// </example>
|
|
public static IServiceCollection AddSvrntyAltchaGrpcVerifier(
|
|
this IServiceCollection services,
|
|
Action<AltchaGrpcOptions> configure)
|
|
{
|
|
services.Configure(configure);
|
|
RegisterCore(services);
|
|
return services;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Binds <see cref="AltchaGrpcOptions"/> from a configuration section
|
|
/// (typically <c>"Altcha:Grpc"</c>) and registers the gRPC verifier
|
|
/// and challenge provider.
|
|
/// </summary>
|
|
public static IServiceCollection AddSvrntyAltchaGrpcVerifier(
|
|
this IServiceCollection services,
|
|
IConfiguration configuration)
|
|
{
|
|
services.Configure<AltchaGrpcOptions>(configuration);
|
|
RegisterCore(services);
|
|
return services;
|
|
}
|
|
|
|
private static void RegisterCore(IServiceCollection services)
|
|
{
|
|
services.AddGrpcClient<AltchaService.AltchaServiceClient>((sp, client) =>
|
|
{
|
|
var opts = sp.GetRequiredService<Microsoft.Extensions.Options.IOptions<AltchaGrpcOptions>>().Value;
|
|
if (string.IsNullOrWhiteSpace(opts.Endpoint))
|
|
throw new InvalidOperationException(
|
|
"Altcha gRPC endpoint not configured. Set AltchaGrpcOptions.Endpoint " +
|
|
"(e.g. http://altcha:9090).");
|
|
client.Address = new Uri(opts.Endpoint);
|
|
});
|
|
|
|
services.TryAddSingleton<IAltchaVerifier, AltchaGrpcVerifier>();
|
|
services.TryAddSingleton<IAltchaChallengeProvider, AltchaGrpcChallengeProvider>();
|
|
}
|
|
}
|