Skip to content

Repository files navigation

Suíte Regulatória BR

open-finance-payments-reference

Implementação de referência production-grade do Iniciador de Pagamento (PISP) do Open Finance Brasil — fluxo de consentimento, criação de pagamento Pix iniciado por terceiro, simulador in-process do banco autorizador (detentor de conta), arquitetura hexagonal validada por ArchUnit, observabilidade end-to-end. mTLS-ready (ICP-Brasil) e roadmap para FAPI Advanced + DPoP em v0.2.0.

Java 21 · Spring Boot 4.0 · Hexagonal · Resilience4j · OpenTelemetry · Grafana

CI License: MIT Java 21 Spring Boot 4.0


Por que este repo existe

O Open Finance Brasil — Fase 4 (Iniciação de Pagamento) permite que um TPP (Third Party Provider, atuando como PISP) inicie um pagamento Pix em nome do usuário, contra o banco detentor da conta — sem o usuário sair do app do iniciador. É o Pix iniciado por terceiro — fundamento de fluxos de checkout one-tap, transferência por aproximação, e recargas em apps de mobilidade/varejo.

Spec é vasta (consent flow + payment flow + FAPI + DCR + ICP-Brasil + JWS sigs) e o material open source de referência em Java é fragmentado. Este repo cobre o núcleo do fluxo com nível de produção e roadmap explícito pros componentes que ainda faltam (FAPI/DPoP/DCR em v0.2.0).

Faz parte da Suíte de Referência Regulatória BR mantida ao lado de:

O que está aqui (v0.1.0 — MVP)

  • Lado iniciador (PISP): criação de consent, consulta de status, criação de payment baseado em consent autorizado, consulta de payment com cadeia completa de status
  • Lado detentor (simulator): endpoints HTTP que mimetizam o banco autorizador — registra consents, autoriza inline (mimics customer SCA approval), recebe pagamentos e agenda settlement assíncrono
  • State machines do domínio:
    • Consent: RCVDAUTHORISEDCONSUMED | REJECTED | REVOKED | EXPIRED
    • Payment Initiation: RCVDPDNGACSPACSC | RJCT
  • EndToEndId ISO 20022 de 32 chars com prefixo E + ISPB do debtor + timestamp + UUID
  • Resilience4j em 2 grupos: holder-consent (rate-limited, retry agressivo) e holder-payment (retry conservador 2 attempts pra evitar duplicar Pix)
  • Audit log estruturado JSON com documento sempre mascarado (Document.masked())
  • Observabilidade rica: Prometheus + Tempo + Loki, OpenTelemetry traces correlacionados por traceId, exemplars Tempo no histograma de latência
  • Hexagonal estrito + ArchUnit — domain puro (sem Spring, sem Jakarta), application só depende de domain, infrastructure implementa ports out
  • mTLS ICP-Brasil-ready via Spring Boot SSL Bundle (config-driven, off por default)
  • CI/CD end-to-end: 7 jobs paralelos GitHub Actions (build, unit, IT, ArchUnit, Semgrep SAST, Trivy image scan, Docker) + CodeQL + Dependency Review + Release tag-driven

Quickstart

git clone https://github.com/Paulo-Marcos-Lucio/open-finance-payments-reference
cd open-finance-payments-reference

make up           # otel + prometheus + tempo + loki + grafana
make run-sim      # app + simulador holder in-process
make load         # tráfego sintético end-to-end

Acesse:

Endpoints PISP

POST /open-banking/payments/v1/consents                  # cria consent
GET  /open-banking/payments/v1/consents/{consentId}      # status do consent
POST /open-banking/payments/v1/pix/payments              # cria payment (consent precisa estar AUTHORISED)
GET  /open-banking/payments/v1/pix/payments/{paymentId}  # status do payment

Endpoints simulator (banco detentor in-process)

POST /sim/holder/consents                                # PISP registra consent no holder
POST /sim/holder/consents/{consentId}/authorise          # autoriza inline (mimic customer SCA)
POST /sim/holder/payments                                # PISP envia payment; settlement assíncrono

Veja requests.http pra exemplos rodáveis na IntelliJ ou via VS Code REST Client.

Arquitetura

Camadas (validadas por ArchUnit em HexagonalArchitectureTest):

  • domain/ — modelos, exceções, ports, state machines. Sem Spring, sem Jakarta
  • application/ — use cases (CreateConsent, GetConsent, AuthoriseConsent, CreatePayment, GetPayment, SettlePayment). Depende apenas de domain/
  • infrastructure/ — implementação dos ports out (HTTP gateway, in-memory repositories, audit, simulator)
  • adapter/web/ — controllers HTTP, DTOs, exception handler, security config

Padrões de implementação destacados

Padrão Onde aplica Por que importa
State machines no domínio Consent, PaymentInitiation Transições válidas explícitas; ArchUnit + tests evitam regressão
Documents mascarados por default Document.masked(), Subject.maskedDocument() Logs/audit nunca expõem CPF/CNPJ completo
Resilience por grupo de operação holder-consent vs holder-payment Consent tolera retry agressivo; payment não — Pix duplicado é incidente regulatório
Simulator-as-controller HolderSimulatorController IT end-to-end no mesmo Spring context, sem Docker, sem WireMock
EndToEndId ISO 20022 EndToEndId.generate() 32 chars exatos, prefixo E + ISPB + timestamp + UUID truncado
Hexagonal estrito + ArchUnit HexagonalArchitectureTest Garantido em CI — não dá pra acidentalmente importar Spring no domain
Sender-constrained mTLS (produção) Spring SSL Bundle Cert ICP-Brasil obrigatório em produção; off em local/test

Configuração

Todos os parâmetros via ofpayments.* em application.yml ou env vars correspondentes.

ofpayments:
  initiator:
    organisation-id: 11111111-1111-1111-1111-111111111111
    software-statement-id: 22222222-2222-2222-2222-222222222222
  holder:
    base-url: ${HOLDER_BASE_URL}
    connect-timeout: 2s
    read-timeout: 5s
  consent:
    default-validity-minutes: 5
    max-validity-minutes: 1440
  payment:
    settle-delay-ms: 250
  simulator:
    failure-rate: 0.0
    jitter-min-ms: 0
    jitter-max-ms: 0
  mtls:
    enabled: true
    bundle-name: ofpayments-prod

FAPI Advanced + DPoP (v0.2.0)

A v0.2.0 adicionou sender-constrained tokens via DPoP (RFC 9449) end-to-end:

# 1) cliente PISP requisita token apresentando DPoP proof (assinado por sua chave)
POST /mock-auth/token
DPoP: <proof_jwt_assinado_pela_ec_key_do_cliente>

→ { "access_token": "...jwt.com.cnf.jkt...", "token_type": "DPoP", "expires_in": 600 }

# 2) cliente usa o token bound + um novo proof a cada request PISP
POST /open-banking/payments/v1/consents
Authorization: DPoP <access_token>
DPoP: <novo_proof_jwt>

→ filter valida: assinatura do proof, htm=POST, htu=URI, iat<60s, jti único, e
   thumbprint(jwk_do_proof) == cnf.jkt do access token. Falha qualquer: 401.

Ativar via profile fapi:

./mvnw spring-boot:run -Dspring-boot.run.profiles=local,simulator,fapi

Sem o profile, comportamento da v0.1.0 (mock auth permitAll) — preserva back-compat.

Roubo de token + replay de outra máquina = 401. Coberto por test (replayedTokenFromAnotherKeyIsRejected).

Detalhes em ADR 0006 — FAPI Advanced + DPoP, incluindo trade-offs aceitos e roadmap pra private_key_jwt/PAR/JARM/DCR/JWS.

Test Coverage & API Docs

Categoria Tests
Unit (incl. ArchUnit + 8 DPoPValidatorTest) 22
Integration (E2E + FAPI E2E) 4
Total 26

JaCoCo coverage report gerado em target/site/jacoco/index.html após ./mvnw verify.

API Documentation (live com a app rodando em http://localhost:8082):

Quando rodando com profile fapi, os endpoints /open-banking/payments/** exigem Authorization: DPoP + header DPoP — Swagger UI vai precisar de um proof JWT válido pra exercitar (use o DPoPHelper de teste como template).

Roadmap

  • v0.1.0 — Consent flow + Payment Initiation + state machines + simulator + observabilidade
  • v0.2.0 — DPoP (RFC 9449) sender-constrained tokens + mock auth server in-process
  • v0.3.0 — private_key_jwt client authentication (RFC 7523) + DCR (Dynamic Client Registration)
  • v0.4.0 — PAR (Pushed Authorization Requests) + JARM (Authorization Response como JWT)
  • v0.5.0 — JWS detached signature em payloads (RFC 7515 + cert ICP-Brasil)
  • v0.6.0 — Webhook receiver pra status callback assíncrono do holder
  • v0.7.0 — Suporte a Pix Automático cross-link com pix-automatico-reference
  • Persistência durável (Postgres com partitioning) — hoje é in-memory
  • Idempotência forte com Idempotency-Key em todos os POSTs
  • Conformance test contra a suite oficial do Open Finance Brasil

Compliance

ADRs em docs/adr/:

Licença

MIT — use, modifique, distribua. Atribuição apreciada.

Autor

Paulo Marcos Lucio — Engenheiro Java pleno · Consultor em integrações regulatórias BR

LinkedIn · GitHub · pmlsp23@gmail.com

Se este repo ajudou seu time, ⭐ uma star — ajuda outros engenheiros do nicho a encontrarem.

About

Implementação de referência Java production-grade do Iniciador de Pagamento (PISP) — Open Finance Brasil Fase 4 · DPoP RFC 9449 · state machines · simulador in-process do detentor de conta. Parte da Suíte de Referência Regulatória BR.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages