Orechio.Platform.Client
1.6.0
dotnet add package Orechio.Platform.Client --version 1.6.0
NuGet\Install-Package Orechio.Platform.Client -Version 1.6.0
<PackageReference Include="Orechio.Platform.Client" Version="1.6.0" />
<PackageVersion Include="Orechio.Platform.Client" Version="1.6.0" />
<PackageReference Include="Orechio.Platform.Client" />
paket add Orechio.Platform.Client --version 1.6.0
#r "nuget: Orechio.Platform.Client, 1.6.0"
#:package Orechio.Platform.Client@1.6.0
#addin nuget:?package=Orechio.Platform.Client&version=1.6.0
#tool nuget:?package=Orechio.Platform.Client&version=1.6.0
Orechio.Platform.Client
Biblioteca client para integração com a Orechio Platform: validação de JWT via JWKS, autorização via Authorization Snapshot da Platform, multi-tenant, multi-branch e reconciliação contínua de permissões.
Fluxo canônico
1. Instalar o package
dotnet add package Orechio.Platform.Client
Ou, em monorepo, via ProjectReference ao
clients/dotnet/Orechio.Platform.Client/src/Orechio.Platform.Client/Orechio.Platform.Client.csproj.
2. AddOrechioPlatform
using Orechio.Platform.Client.Configuration;
builder.Services.AddOrechioPlatform(options =>
{
options.Application = "minha-app"; // slug no IdentityService
options.PlatformUrl = new Uri("https://identity.suaempresa.com"); // deriva JWKS/Authorization Snapshot/Registry
options.Issuer = "https://identity.suaempresa.com";
options.ApplicationId = Guid.Parse("<GUID da app no IdentityService>"); // obrigatório
options.ApiKey = builder.Configuration["Platform:ApiKey"]!; // X-Api-Key do sync
options.Permissions =
[
new("members.read", "Ver membros"),
new("members.write", "Gerenciar membros"),
];
options.RolesTemplate =
[
new("Admin", ["members.read", "members.write", PlatformSharedPermissions.ViewTenants]),
];
});
3. Options — o que cada campo faz
| Campo | Obrigatório | Efeito |
|---|---|---|
PlatformUrl |
sim | URL base única; deriva /.well-known/jwks.json, /access/authorization-snapshot, /api/registry/sync(-status) |
Application |
sim | Slug da aplicação no IdentityService (usado no registry, não como identificador de auth) |
Issuer |
sim | Claim iss esperado no JWT |
ApplicationId |
sim | Claim aud esperado — rejeita tokens emitidos para outra aplicação |
ApiKey |
não* | Header X-Api-Key para POST /api/registry/sync — *obrigatório se Permissions/RolesTemplate forem declarados |
Permissions / RolesTemplate |
não | Manifest reconciliado continuamente com o IdentityService (ver passo 8) |
BranchHeader |
não (default X-Branch-Id) |
Header lido para a branch ativa explícita |
ErrorContract |
não (default V2) |
V2 = OrechioProblemDetails/application/problem+json; Legacy = {code,message} ad-hoc/application/json |
AuthorizationSnapshotCacheDuration |
não (default 60s) | TTL do cache local de permissões |
JwksCacheDuration |
não (default 30min) | Intervalo do refresh assíncrono de chaves em segundo plano |
RegistryReconciliationInterval / ...FailureRetryInterval |
não (default 5min / 30s) | Cadência da reconciliação contínua (passo 8) |
4. Middleware — ordem obrigatória
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.UseOrechioPlatform(); // TenantValidation → BranchResolver → PermissionMiddleware (compat)
app.MapControllers();
app.Run();
Inverter a ordem resulta em middlewares de contexto/permissão executando antes da
validação do token. UseOrechioPlatform() nunca chama UseAuthentication/UseAuthorization
nem mapeia rota alguma — só registra os três middlewares do Client.
5. RequireTenant()
app.MapGet("/publico", Handler); // token parcial (sem tenant_id) ok
app.MapGet("/pedidos", Handler).RequireTenant(); // exige tenant_id válido no token
tenant_id vem do claim do token, resolvido pelo fluxo POST /auth/select-tenant do
IdentityService. Sem autenticação: 401. Autenticado sem tenant_id: 403.
6. RequireBranch()
app.MapPost("/pedidos", Handler).RequireBranch(); // exige tenant + branch ativa válida
RequireBranch() já implica RequireTenant(). Branch ativa é resolvida a partir do
header BranchHeader (passo 3), do claim branch_id, ou por auto-seleção quando há
exatamente uma branch autorizada:
| Situação | Branch ativa |
|---|---|
| 0 branches autorizadas | nenhuma (null) |
| 1 branch autorizada | selecionada automaticamente |
| 2+ branches, sem header/claim de seleção | nenhuma (null) — nunca a primeira da lista |
| 2+ branches, header ou claim válidos | a branch selecionada |
| header/claim fora das branches autorizadas | rejeitado (403) |
7. RequirePermission(...)
app.MapGet("/pedidos", Handler).RequirePermission("pedidos.read");
Usa o pipeline padrão de ASP.NET Core Authorization (nunca reimplementa checagem manual).
Permissões são resolvidas via um Authorization Snapshot buscado na Platform
(GET access/authorization-snapshot, reencaminhando o Bearer token do próprio chamador)
e cacheado localmente em memória — nunca via Redis. A Platform é a única fonte de verdade
de permissões efetivas; system.admin é a única permissão central equivalente a "acesso
total" — nenhuma role local concede bypass.
Falha da Platform nunca vira acesso concedido: sem snapshot válido em cache e a Platform indisponível/rejeitando = 403 (fail-closed). Com um snapshot ainda válido em cache, a Platform pode ficar indisponível sem interromper as requisições.
Tokens são validados contra o JWKS do issuer antes de qualquer checagem de permissão. As
signing keys são mantidas em cache local (memória), atualizado de forma inteiramente
assíncrona em segundo plano — a resolução de chave usada durante a validação do token
nunca faz uma chamada de rede bloqueante. Um kid desconhecido dispara um refresh
assíncrono throttled (a primeira requisição pode ver um 401 transitório, sem restart —
ver docs/architecture/004-platform-sdk.md); a Platform ficar indisponível não invalida
chaves já conhecidas, mas também nunca aceita um kid que nunca foi publicado.
8. Reconciliação de registry
Ativa automaticamente quando ApiKey, PlatformUrl e ao menos uma permissão própria em
Permissions são configurados (passo 2). RolesTemplate pode referenciar permissões
próprias ou permissões compartilhadas listadas em PlatformSharedPermissions.Codes; a app
continua proibida de declarar system.* em Permissions, e system.admin não é
compartilhada. O client reconcilia continuamente (não só no startup) o manifest desejado
com o estado registrado no IdentityService: consulta GET /api/registry/sync-status,
compara o hash local do manifest com o hash remoto e só chama POST /api/registry/sync
(header X-Api-Key) quando divergem — nenhuma escrita desnecessária. Falhas nunca
encerram a reconciliação; a próxima tentativa continua agendada
(RegistryReconciliationInterval normal, ...FailureRetryInterval após falha).
9. Health check
app.MapHealthChecks("/health");
AddOrechioPlatform registra RegistryReconciliationHealthCheck no DI automaticamente
(quando a reconciliação está ativa) — mapear a rota com app.MapHealthChecks(...)
continua responsabilidade do consumidor. Estados: Healthy (em sincronia),
Degraded (tentando reconectar), Unhealthy (divergência persistente/erro).
10. Configuração — erro e Content-Type
Falhas geradas pelo Client (tenant/branch/permission ausentes, autenticação necessária)
chegam no contrato OrechioProblemDetails (code, message, status, correlation_id,
errors?) como application/problem+json — o default de AddOrechioPlatform
(options.ErrorContract = PlatformErrorContract.V2). O correlation_id permite cruzar
os logs do seu app com os do IdentityService.
{
"code": "permission.denied",
"message": "Você não tem permissão para executar esta ação.",
"status": 403,
"correlation_id": "...",
"errors": { "required": ["pedidos.create"] }
}
11. Migrando do legado
AddIdentityClient/UseIdentityClient (e o namespace Orech.Identity.Client.*)
continuam funcionando sem alteração — convergem para a MESMA infraestrutura de DI que
AddOrechioPlatform/UseOrechioPlatform (nunca duas composições paralelas, nunca dois
JWKS refresh services ou dois Registry reconcilers). Migração sem big bang:
| Legado | Canônico | Nota |
|---|---|---|
AddIdentityClient(o => { o.IdentityServiceUrl = ...; o.JwksUri = ...; }) |
AddOrechioPlatform(o => { o.PlatformUrl = ...; }) |
PlatformUrl único deriva JWKS/Authorization Snapshot/Registry — não precisa mais configurar cada URL separadamente |
UseIdentityClient() |
UseOrechioPlatform() |
Mesmos três middlewares, mesma ordem — equivalentes |
options.ErrorContract (default Legacy) |
options.ErrorContract (default V2) |
Legado preserva {code,message}/application/json byte-a-byte; troque para V2 explicitamente se quiser OrechioProblemDetails no path legado |
options.RedisConnection |
— (removido da fachada canônica) | [Obsolete], inerte desde P12.2 — permissões vêm do Authorization Snapshot, nunca de Redis |
options.AdminRoles |
— (removido da fachada canônica) | [Obsolete], sem bypass desde P12.2 — use system.admin no Authorization Snapshot |
Orech.Identity.Client.ICurrentUser |
Orechio.Platform.Client.ICurrentUser |
Wrapper [Obsolete] delega para o tipo canônico |
Pode migrar app por app, ou endpoint por endpoint dentro da mesma app — os dois caminhos coexistem no mesmo processo sem conflito.
Requer .NET 10. Consulte o INTEGRATION-GUIDE.md para o onboarding completo de uma app
nova e CHANGELOG.md para o histórico de mudanças por versão.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.AspNetCore.Authentication.JwtBearer (>= 10.0.12)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Orechio.Platform.Client:
| Package | Downloads |
|---|---|
|
Orechio.Platform.Bff.Account
Shared account onboarding BFF for Orechio products: signup verification, first-branch provisioning, password recovery and invites, mounted on the product's own domain so the session cookie stays first-party. |
GitHub repositories
This package is not used by any popular GitHub repositories.