Guia — IInboundAuthScheme

Um esquema de autenticação novo, ativado por scheme: num spec.auth.schemes. Os quatro esquemas embutidos (jwt, oidc, mtls, basic — ver Autenticação e autorização) são implementados exatamente pelo mesmo contrato descrito aqui.

Exemplo mínimo

using Microsoft.AspNetCore.Authentication;
using Microsoft.OpenApi;
using Pipevine.Core.Configuration;
using Pipevine.Model.Auth;
using Pipevine.Security.Abstractions;
using Pipevine.Security.Abstractions.Secrets;

public sealed class AcmeInboundAuthScheme(ISecretResolverRegistry secretResolvers) : IInboundAuthScheme
{
    // Roda UMA vez por esquema declarado, no startup — antes do host subir. Lançar aqui derruba
    // o startup, não uma requisição.
    public void Configure(AuthenticationBuilder builder, AuthSchemeDefinition definition)
    {
        var config = PipevineNodeJsonConverter.ToJsonNode(definition.Config);
        var secretRef = config?["secret"]?.GetValue<string>()
            ?? throw new InvalidOperationException($"Scheme '{definition.Id}': requer 'secret'.");

        // Credencial nunca literal no YAML — sempre ${secret:...}.
        if (!SecretReference.IsSecretReference(secretRef))
        {
            throw new InvalidOperationException($"Scheme '{definition.Id}': 'secret' precisa ser ${{secret:...}}.");
        }

        var secret = SecretReference.ResolveAsync(secretRef, secretResolvers, CancellationToken.None).AsTask().GetAwaiter().GetResult();

        builder.AddScheme<AcmeSchemeOptions, AcmeAuthenticationHandler>(definition.Id, options =>
        {
            options.Secret = secret;
        });
    }

    // Opcional, mas fortemente recomendado — é o que faz o esquema aparecer no Swagger gerado.
    public OpenApiSecurityScheme? DescribeForOpenApi(AuthSchemeDefinition definition) => new()
    {
        Type = SecuritySchemeType.ApiKey,
        In = ParameterLocation.Header,
        Name = "X-Acme-Signature",
    };
}

O AuthenticationHandler<TOptions> em si é ASP.NET Core puro — nenhuma API específica do Pipevine além de receber a claims principal em input.claims (via IPrincipalProjector, abaixo).

Ativação

spec:
  auth:
    default: { scheme: acme, ref: partner-acme }
    schemes:
      - { id: partner-acme, scheme: acme, secret: "${secret:env:ACME_SHARED_SECRET}" }
services.AddPipevineSecurity(); // idempotente
services.AddKeyedSingleton<IInboundAuthScheme, AcmeInboundAuthScheme>("acme");

Complementos

  • IAuthorizationRule — novas formas de autorização além de scopes/roles/claims/expr.
  • IPrincipalProjector — controla como as claims chegam em input.claims. O padrão projeta todas as claims do ClaimsPrincipal; um esquema pode registrar o seu próprio para achatar/renomear campos.

Regra absoluta: nunca aceite credencial literal

Toda credencial de um esquema (senha, chave de assinatura, segredo de cliente) precisa ser exigida como referência ${secret:...}, nunca como valor literal no YAML — os quatro esquemas embutidos (veja basic, por exemplo) derrubam o build com uma mensagem clara quando encontram um literal onde uma referência é esperada. Um esquema de terceiro deve seguir a mesma regra.

Para onde ir daqui