Pular para o conteúdo principal

Em outra linguagem: o protocolo de runtime

O runtime da aplicação — ler quem entrou e consultar o QueryMesh — existe pronto no SDK de TypeScript (@nnumbers/zero/app e @nnumbers/zero/react). O SDK publicado de Go é o cliente da API de gerenciamento, não o runtime; uma aplicação em outra linguagem segue o protocolo de runtime, que é o contrato entre a plataforma e o código da aplicação e está descrito nesta página.

A identidade de quem entrou​

A cada requisição que chega pela borda, a plataforma põe em X-NNumbers-Identity um JWS compacto — cabeçalho alg: ES256, typ: nn-identity+jwt, kid — com o payload abaixo. Sem pessoa autenticada, o cabeçalho não vem. Um valor mandado pelo navegador é removido antes de qualquer outra coisa.

A aplicação sempre confere:

  1. a assinatura, com as chaves públicas do broker (NNUMBERS_IDENTITY_JWKS; e NNUMBERS_BROKER_URL/v1/jwks quando chega um kid desconhecido) — guarde as chaves por alguns minutos e não busque de novo a cada requisição;
  2. iss igual a NNUMBERS_IDENTITY_ISSUER;
  3. aud igual a NNUMBERS_APP_ID — a identidade entregue a outra aplicação não vale aqui;
  4. org igual a NNUMBERS_ORG_ID;
  5. nbf e exp, com até 60 s de tolerância de relógio — a identidade vale por 5 minutos.

Um cabeçalho sem assinatura conferida não prova nada: há caminhos que chegam à aplicação sem passar pela borda (o mesmo namespace, as permissões de rede, a entrada interna). Sem o cabeçalho, a requisição é anônima; com o cabeçalho e qualquer conferência falhando, recuse — nunca trate como pessoa.

ClaimO que é
iss, aud, jtio emissor, a aplicação desta identidade e o identificador dela
subo sujeito da pessoa no IAM da organização
org, org_sluga organização
iamo emissor do IAM da organização
sida sessão na plataforma — referência opaca, não é o cookie
name, email, email_verified, preferred_usernamequando a conta os tem
iat, nbf, expo prazo; exp é 5 minutos depois de iat

Os caminhos reservados​

Os caminhos em /.nnumbers/ são servidos pela plataforma no endereço da própria aplicação — nunca chegam ao código dela:

Método e caminhoResposta
GET /.nnumbers/auth/login?return_to=<caminho>302 para o login do IAM da organização
GET /.nnumbers/auth/callback302 de volta ao return_to, com a sessão criada
POST /.nnumbers/auth/logout303 para /, com a sessão da aplicação encerrada; exige Origin do próprio endereço
GET /.nnumbers/auth/session203 {"user": {...} | null, "organization": {"id", "slug"}}
GET /.nnumbers/v1/context203 {"app": {"id"}, "organization": {"id", "slug"}, "auth": {"login_path", "logout_path"}}

return_to só aceita caminho do próprio endereço (começa com /, não com //). Os JSON vêm com 203, não 200, e Cache-Control: no-store — é como a borda repassa a resposta da plataforma, e o navegador lê 203 como sucesso.

Sair é da aplicação: encerra a sessão dela, e o login único da organização continua — entrar de novo não pede senha enquanto ele durar.

O broker, de dentro do cluster​

NNUMBERS_BROKER_URL só é alcançável de dentro do cluster. A aplicação o usa para as duas operações:

Método e caminhoO que faz
GET /v1/jwksas chaves públicas que assinam a identidade
POST /v1/querymesh/querycom X-NNumbers-Identity da requisição, executa a consulta no QueryMesh da organização em nome daquela pessoa e devolve colunas e linhas

A consulta leva a SQL e, opcionalmente, o teto de linhas:

POST {NNUMBERS_BROKER_URL}/v1/querymesh/query
X-NNumbers-Identity: <a identidade da requisição, já conferida>
Content-Type: application/json

{"sql": "SELECT name, regionkey FROM tpch.tiny.nation", "max_rows": 1000}
CampoO que é
sqla consulta (obrigatória); nunca vai para log
max_rowso teto de linhas trazidas, de 1 a 100.000 (padrão 100.000); acima dele, a consulta é cancelada no QueryMesh

O endereço do QueryMesh é o que o administrador da organização configurou (zero orgs integrations set querymesh --url https://…); a aplicação não o escolhe. Quem consulta é a plataforma, com o token da sessão da pessoa, direto — sem troca de token —, e o token não sai da plataforma. Sem pessoa, não há consulta: nenhum caminho cai para uma credencial "da aplicação".

O sucesso devolve as colunas, com o tipo do Trino, e as linhas, na ordem das colunas:

{
"columns": [{"name": "name", "type": "varchar"}, {"name": "regionkey", "type": "bigint"}],
"rows": [["BRAZIL", 1]]
}

As recusas vêm como {"code", "message"}:

StatusCódigoQuandoO que fazer
400VALIDATION_FAILEDsem SQL, ou max_rows fora de 1–100.000corrija o pedido e repita
401USER_SESSION_REQUIREDsem identidade, ou a sessão de quem entrou terminouleve a pessoa ao login e repita
401IDENTITY_ASSERTION_INVALIDa identidade não confere (assinatura, emissor, prazo, organização, aplicação)use a identidade que a plataforma entrega; não trate como pessoa
409ORGANIZATION_INTEGRATION_NOT_CONFIGUREDa organização não tem o QueryMesh configurado, ou ele está desligadoo administrador da organização configura
409QUERYMESH_NOT_ENABLEDa aplicação não ligou a capacidade querymeshzero services enable querymesh <serviço> — vale na hora
502QUERYMESH_IDENTITY_REJECTEDo QueryMesh não aceitou o token de quem entrou (emissor, audiência ou scope)quando falta ao realm o scope que o QueryMesh exige, quem resolve é a administração da plataforma — entrar de novo não resolve
403QUERYMESH_ACCESS_DENIEDas políticas de dados da organização negaram a consulta a esta pessoapeça o acesso ao administrador de dados
422 ou 502QUERYMESH_QUERY_FAILED422: o QueryMesh recusou a consulta ou o resultado passou do teto; 502: o QueryMesh respondeu fora do protocolo ou mandou continuar fora do endereço configuradoconfira a consulta e repita; no 502, fale com quem administra o QueryMesh
503QUERYMESH_UNAVAILABLEo QueryMesh não respondeu ou está ocupado, ou a plataforma está no limite de consultasrepita em instantes
503APPLICATION_IDENTITY_NOT_READYo broker não tem as chaves disponíveis agorarepita; se persistir, zero services doctor organization-iam <serviço>

O que a aplicação nunca recebe​

Segredo de cliente (não existe: o client de login é público), token de renovação, o token de acesso do IAM — nem para o QueryMesh, porque quem consulta é a plataforma —, e nenhum meio de escolher a pessoa.

Próximos passos​