# Integracao SSO com Core Banking

Integracao de autenticacao unica (Single Sign-On) entre o Monetarie PIX e o Monetarie Core Banking, usando JWT compartilhado com Guardian HS256.

## Pre-requisitos

- Monetarie Core Banking operacional com Guardian JWT configurado
- Shared secret definido e compartilhado entre Core e PIX
- Kubernetes secret `monetarie-shared-jwt-secret` criado no namespace `pix`
- Entendimento basico de JWT (JSON Web Tokens) e HS256

## Visao Geral da Arquitetura SSO

```mermaid
sequenceDiagram
    participant USER as Usuario
    participant CORE as Core Banking<br/>Guardian JWT
    participant SSO as Backoffice<br/>SSO Hub
    participant PIX as Monetarie PIX<br/>Settlement Service

    rect rgb(230, 245, 255)
        Note over USER,CORE: Fluxo 1: Core Guardian Token
        USER->>CORE: Login (CPF + senha)
        CORE->>CORE: Gerar JWT (iss: "monetarie")
        CORE-->>USER: JWT token
        USER->>PIX: Requisicao + JWT
        PIX->>PIX: JWTAuth verifica com shared secret
        PIX-->>USER: HTTP 200 (autorizado)
    end

    rect rgb(255, 245, 230)
        Note over USER,SSO: Fluxo 2: SSO Hub Token
        USER->>SSO: Login centralizado
        SSO->>SSO: Gerar JWT (iss: "monetarie-sso", target: "pix")
        SSO-->>USER: JWT token
        USER->>PIX: Requisicao + JWT
        PIX->>PIX: SsoAuth verifica iss + target_system
        PIX-->>USER: HTTP 200 (autorizado)
    end
```

## Formato do Token JWT

### Token Core Guardian (iss: "monetarie")

```json
{
  "alg": "HS256",
  "typ": "JWT"
}
.
{
  "iss": "monetarie",
  "sub": "550e8400-e29b-41d4-a716-446655440000",
  "aud": "monetarie",
  "exp": 1739462400,
  "iat": 1739376000,
  "jti": "unique-token-id",
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "admin@monetarie.com.br",
    "role": "admin"
  }
}
```

### Token SSO Hub (iss: "monetarie-sso")

```json
{
  "alg": "HS256",
  "typ": "JWT"
}
.
{
  "iss": "monetarie-sso",
  "sub": "550e8400-e29b-41d4-a716-446655440000",
  "aud": "monetarie",
  "exp": 1739462400,
  "iat": 1739376000,
  "jti": "unique-token-id",
  "target_system": "pix",
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "admin@monetarie.com.br",
    "role": "admin"
  }
}
```

## Validacao de Issuer

O Monetarie PIX aceita tokens de dois issuers:

| Issuer | Validacao `target_system` | Cenario |
|--------|--------------------------|---------|
| `"monetarie"` | Nao requerido | Token direto do Core Banking |
| `"monetarie-sso"` | Deve ser `"pix"` | Token do SSO Hub (Backoffice) |

### Fluxo de Validacao no SsoAuth

```mermaid
graph TD
    A[Token JWT recebido] --> B{Decodificar com<br/>shared secret}
    B -->|Falha| Z[HTTP 401]
    B -->|Sucesso| C{Verificar issuer}
    C -->|iss = "monetarie"| D[Aceitar<br/>sem target_system check]
    C -->|iss = "monetarie-sso"| E{target_system = "pix"?}
    C -->|outro| Z
    E -->|Sim| D
    E -->|Nao| Z
    D --> F{Token expirado?}
    F -->|Sim| Z
    F -->|Nao| G{Token no blacklist?}
    G -->|Sim| Z
    G -->|Nao| H[HTTP 200 — Autorizado]

    style Z fill:#e74c3c,color:#fff
    style H fill:#27ae60,color:#fff
```

## Cadeia de Fallback do Secret

O Monetarie PIX busca o secret JWT na seguinte ordem de prioridade:

```
1. JWT_SECRET          (variavel de ambiente especifica)
2. GUARDIAN_SECRET_KEY  (compartilhado com Core Banking)
3. SECRET_KEY_BASE     (fallback Phoenix padrao)
```

Modulos que usam esta cadeia:

| Modulo | Arquivo | Funcao |
|--------|---------|--------|
| `Shared.Auth.JwtAuth` | `shared/lib/shared/auth/jwt_auth.ex` | `jwt_secret/0` |
| `Shared.Auth.SsoAuth` | `shared/lib/shared/auth/sso_auth.ex` | `jwt_secret/0` |
| `DictService.Plugs.Authenticate` | `dict_service/lib/dict_service_web/plugs/authenticate.ex` | `jwt_secret/0` |
| `DictServiceWeb.AuthController` | `dict_service/lib/dict_service_web/controllers/auth_controller.ex` | `jwt_secret/0` |
| `Shared.Auth.MFA` | `shared/lib/shared/auth/mfa.ex` | `jwt_secret/0` |

## Configuracao Kubernetes

### Criar Shared Secret

```bash
# O secret deve ter o mesmo valor que o SECRET_KEY_BASE do Core Banking
# Em dev, Core usa: "dev-only-secret-key-not-for-production"

# Criar secret no namespace pix
kubectl create secret generic monetarie-shared-jwt-secret -n pix \
  --from-literal=guardian-secret-key="$(kubectl get secret core-secrets -n core -o jsonpath='{.data.secret-key-base}' | base64 -d)"

# Verificar
kubectl get secret monetarie-shared-jwt-secret -n pix
# Saida esperada:
# NAME                        TYPE     DATA   AGE
# monetarie-shared-jwt-secret    Opaque   1      5s
```

### Referenciar no Deploy

```yaml
# deploy/backend.yaml
env:
  - name: GUARDIAN_SECRET_KEY
    valueFrom:
      secretKeyRef:
        name: monetarie-shared-jwt-secret
        key: guardian-secret-key
```

## Teste Local de SSO

Para testar a integracao SSO localmente sem o Core Banking real:

### 1. Configurar mesmo secret

```bash
# .env do PIX (backend)
JWT_SECRET=dev-only-secret-key-not-for-production

# Este e o mesmo valor que o Core Banking usa em dev
```

### 2. Gerar token manualmente

```elixir
# Via iex (PIX backend)
iex -S mix

# Gerar token Core Guardian
payload = %{
  "iss" => "monetarie",
  "sub" => "test-user-id",
  "exp" => System.system_time(:second) + 3600,
  "iat" => System.system_time(:second),
  "jti" => Ecto.UUID.generate(),
  "user" => %{
    "id" => "test-user-id",
    "email" => "admin@monetarie.com.br",
    "role" => "admin"
  }
}

secret = System.get_env("JWT_SECRET", "dev-only-secret-key-not-for-production")
signer = Joken.Signer.create("HS256", secret)
{:ok, token, _claims} = Joken.encode_and_sign(payload, signer)
IO.puts(token)
```

### 3. Testar com curl

```bash
# Usando token Core Guardian
TOKEN="eyJhbGciOiJIUzI1NiIs..."

curl -s https://pixapi-dev.fluxiq.com.br/api/v1/auth/me \
  -H "Authorization: Bearer ${TOKEN}" | jq .

# Saida esperada:
# {
#   "id": "test-user-id",
#   "email": "admin@monetarie.com.br",
#   "role": "admin"
# }
```

### 4. Testar token SSO Hub

```elixir
# Gerar token SSO Hub (requer target_system)
payload = %{
  "iss" => "monetarie-sso",
  "sub" => "test-user-id",
  "exp" => System.system_time(:second) + 3600,
  "iat" => System.system_time(:second),
  "jti" => Ecto.UUID.generate(),
  "target_system" => "pix",
  "user" => %{
    "id" => "test-user-id",
    "email" => "admin@monetarie.com.br",
    "role" => "admin"
  }
}

secret = System.get_env("JWT_SECRET", "dev-only-secret-key-not-for-production")
signer = Joken.Signer.create("HS256", secret)
{:ok, token, _claims} = Joken.encode_and_sign(payload, signer)
```

## Token Blacklist

Quando um usuario faz logout, o token JWT e adicionado ao blacklist no Redis:

```
Chave: blacklist:{jti}
Valor: "1"
TTL: tempo restante do token (exp - now)
```

O blacklist e verificado em:

- `Shared.Auth.JwtAuth` — Settlement Service
- `DictService.Plugs.Authenticate` — Dict Service

```bash
# Verificar se um token esta no blacklist
redis-cli -h 10.140.240.4 GET "blacklist:unique-token-id"
# Saida: "1" (blacklisted) ou (nil) (valido)
```

## RBAC com SSO

Tokens Core Guardian que chegam via SSO tem RBAC aplicado normalmente:

1. Token decodificado pelo `JwtAuth` ou `SsoAuth`
2. User ID extraido do claim `sub`
3. `RequirePermission` plug verifica permissoes na tabela `monetarie_auth.group_features`
4. Se usuario SSO nao tem grupo no PIX, RBAC faz fail-closed (403)

Para conceder permissoes a usuarios SSO:

```bash
# Criar grupo para usuarios Core
psql -h 10.140.241.2 -U postgres -d monetarie -c "
  INSERT INTO monetarie_auth.groups (id, name, description) VALUES
  (gen_random_uuid(), 'core_banking_users', 'Usuarios do Core Banking via SSO');
"

# Conceder permissoes
psql -h 10.140.241.2 -U postgres -d monetarie -c "
  INSERT INTO monetarie_auth.group_features (group_id, feature_name, can_read, can_write)
  SELECT g.id, feature, true, false
  FROM monetarie_auth.groups g,
       unnest(ARRAY['transactions', 'keys', 'settlements']) AS feature
  WHERE g.name = 'core_banking_users';
"

# Associar usuario SSO ao grupo
psql -h 10.140.241.2 -U postgres -d monetarie -c "
  INSERT INTO monetarie_auth.user_groups (user_id, group_id)
  SELECT 'sso-user-uuid', g.id
  FROM monetarie_auth.groups g
  WHERE g.name = 'core_banking_users';
"
```

## Troubleshooting SSO

| Sintoma | Causa | Solucao |
|---------|-------|---------|
| 401 em todos os tokens Core | Secret diferente entre Core e PIX | Verificar `GUARDIAN_SECRET_KEY` no PIX = `SECRET_KEY_BASE` no Core |
| 401 em tokens SSO Hub | `target_system` ausente ou diferente de `"pix"` | Verificar payload do token SSO |
| 403 apos autenticacao | Usuario sem grupo no PIX | Criar grupo e associar usuario |
| Token funciona mas expira rapido | `exp` muito curto | Verificar configuracao de TTL no Core |
| "Token revoked" | Token no blacklist Redis | Fazer novo login |

## Resultado Esperado

Ao implementar esta integracao SSO, voce tera:

- Autenticacao transparente entre Core Banking e PIX via JWT compartilhado
- Suporte a tokens de dois issuers (Core Guardian e SSO Hub)
- Cadeia de fallback para o secret JWT (3 niveis)
- Token blacklist compartilhado via Redis
- RBAC aplicado a usuarios SSO com fail-closed
- Procedimento de teste local sem dependencia do Core Banking real
