@authyon/server 0.2.0-beta.14 → 0.2.0-beta.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -120,7 +120,7 @@ await authyon.environment.audit.list({ take: 50 });
120
120
 
121
121
  Veja [`examples/organizationMembership.ts`](./examples/organizationMembership.ts) para o fluxo completo, incluindo as rotas de backend que o `@authyon/auth` chamaria.
122
122
 
123
- Namespaces disponíveis: `environment.users`, `environment.tenants` (com `.members` e `.roles` aninhados), `environment.roles`, `environment.permissions`, `environment.audit`, `environment.financialAuthorizations`.
123
+ Namespaces disponíveis: `environment.users`, `environment.tenants` (com `.members` e `.roles` aninhados), `environment.roles`, `environment.permissions`, `environment.audit`. OTP e aprovações ficam em `security` (veja abaixo).
124
124
 
125
125
  ## Autorização local
126
126
 
@@ -191,34 +191,37 @@ Chamadas server-side propagam `clientIp` em `X-Forwarded-For`. O middleware Expr
191
191
  await authyon.validate(token, { clientIp: "203.0.113.10" });
192
192
  ```
193
193
 
194
- ## Confirmação de transações financeiras
194
+ ## Segurança (`security.*`)
195
195
 
196
- Exige uma credencial de ambiente com o escopo `authyon:financial:authorize`. Guia
197
- completo, incluindo o lado do cliente: [`docs/financialStepUp.md`](../../docs/financialStepUp.md).
196
+ OTP e aprovações ficam agrupados em `authyon.security`. Exige uma credencial de ambiente
197
+ com o escopo `authyon:otp:verify` (para `security.otp`) e/ou `authyon:financial:authorize`
198
+ (para `security.approvals`). Guia completo:
199
+ [`docs/security-otp-approvals.md`](../../docs/security-otp-approvals.md).
198
200
 
199
201
  ```ts
200
- const transaction = {
201
- action: "pix.transfer",
202
- amount: 150.5,
203
- currency: "BRL",
204
- beneficiary: "Maria Silva",
205
- };
206
-
207
- // 1. Antes de executar, peça a aprovação do cliente.
208
- const { id } = await authyon.environment.financialAuthorizations.create({
209
- ...transaction,
202
+ // security.otp — só validar o código do app autenticador
203
+ const result = await authyon.security.otp.check(customerId, code);
204
+ if (!result.valid) console.log(result.attemptsRemaining, result.sessionsRevoked);
205
+
206
+ // security.approvals — aprovação presa a um payload livre e de uso único
207
+ const { id } = await authyon.security.approvals.create({
210
208
  subjectId: customerId,
211
- idempotencyKey: orderId,
209
+ payload: { type: "pix", amount: 150.5, to: "maria@example.com" },
212
210
  });
213
-
214
- // 2. O cliente confirma com o código (@authyon/auth → financialAuthorizations.confirm).
215
-
216
- // 3. Consuma com a mesma transação e só então execute.
217
- const { assurance } = await authyon.environment.financialAuthorizations.consume(id, transaction);
211
+ // ...cliente confirma com @authyon/auth → security.approvals.confirm
212
+ const { payload } = await authyon.security.approvals.consume(id);
218
213
  ```
219
214
 
220
- Se o seu servidor guarda o token do cliente (BFF), o lado do cliente também está em
221
- `authyon.user(accessToken).financialAuthorizations`.
215
+ | Método | Endpoint |
216
+ | ------------------------------------ | --------------------------------------- |
217
+ | `security.otp.check(userId, code)` | `POST /env/users/{userId}/otp/verify` |
218
+ | `security.approvals.create(input)` | `POST /env/authorizations` |
219
+ | `security.approvals.get(id)` | `GET /env/authorizations/{id}` |
220
+ | `security.approvals.consume(id, p?)` | `POST /env/authorizations/{id}/consume` |
221
+
222
+ Cada código vale uma vez; 3 erros seguidos deslogam o usuário de todos os dispositivos e
223
+ 5 bloqueiam a verificação por 15 minutos. Se o seu servidor guarda o token do cliente
224
+ (BFF), o lado do cliente está em `authyon.user(accessToken).security.approvals`.
222
225
 
223
226
  ## Administração por tenant (`tenant()`)
224
227
 
@@ -371,12 +374,58 @@ await authyon.environment.tenants.members.remove(tenantId, userId);
371
374
  // Os métodos tenant(credentials).members.add/remove existentes continuam disponíveis.
372
375
  ```
373
376
 
374
- Configure `envKey` para `user()`. O convite de tenant associa um usuário já
377
+ Configure `envKey` para `user()`. `members.invite` associa um usuário já
375
378
  cadastrado no ambiente pelo e-mail; não cria conta e não envia link por e-mail.
379
+ Para isso, use os convites abaixo.
376
380
  A API exige associação/permissões do usuário chamador. No browser, os métodos
377
381
  existentes `@authyon/auth` → `organization.members.invite/remove` continuam
378
382
  atendendo esse fluxo. Nunca importe `@authyon/server` no browser.
379
383
 
384
+ ## Convites de tenant (e-mail ou link)
385
+
386
+ Convide um e-mail que talvez ainda não tenha conta — aceitar cria a conta, já com o
387
+ e-mail confirmado. A resposta sempre traz o `acceptUrl` completo; `sendEmail: false`
388
+ só gera o link para você enviar pelo seu canal.
389
+
390
+ ```ts
391
+ // Pelo ambiente (escopo authyon:users:write; listar exige authyon:tenants:read).
392
+ const invite = await authyon.environment.tenants.invites.create(tenantId, {
393
+ email: "pessoa@example.com",
394
+ roles: ["reader"],
395
+ sendEmail: false, // padrão: true
396
+ // Opcional: para onde mandar a pessoa depois de aceitar. Precisa estar
397
+ // cadastrado (match exato) nos redirect URIs do ambiente.
398
+ redirectUri: "https://app.example.com/bem-vindo",
399
+ });
400
+ invite.acceptUrl; // só aparece aqui — a API guarda apenas o hash do token
401
+
402
+ await authyon.environment.tenants.invites.list(tenantId);
403
+ await authyon.environment.tenants.invites.resend(tenantId, invite.id, { sendEmail: true });
404
+ await authyon.environment.tenants.invites.revoke(tenantId, invite.id);
405
+
406
+ // Pela credencial do tenant, ou agindo como o usuário (permissão tenants:members:invite).
407
+ await authyon.tenant(credentials).invites.create({ email: "pessoa@example.com" });
408
+ await authyon.user(token).tenants.invites.create(tenantId, { email: "pessoa@example.com" });
409
+
410
+ // Página de aceite no seu backend: públicas, usam só o envKey.
411
+ const preview = await authyon.environment.tenants.invites.preview(token);
412
+ const accepted = await authyon.environment.tenants.invites.accept({
413
+ token,
414
+ password: preview.accountExists ? undefined : password,
415
+ // Opcional. Com metadata, a chamada vai para /env/tenant-invites/accept usando
416
+ // clientId/clientSecret (escopo authyon:users:write) — só o backend pode definir.
417
+ publicMetadata: { plano: "pro" },
418
+ privateMetadata: { crmId: "42" },
419
+ // customFields: { ... } — obsoleto, prefira os metadata acima.
420
+ });
421
+ if (accepted.redirectUri) redirect(accepted.redirectUri); // o redirect fica por sua conta
422
+ ```
423
+
424
+ O link vale 7 dias e uma única vez. `resend` gera um link novo e invalida o anterior.
425
+ Por padrão o link aponta para a página do Authyon; configure a _URL do convite para
426
+ tenant_ nas configurações do ambiente para usar a sua (ela recebe `token` e `env`).
427
+ Aceitar não faz login.
428
+
380
429
  ## Compatibilidade e segurança do transporte
381
430
 
382
431
  As chamadas exigem os endpoints externos atuais da API e a migração
@@ -1,4 +1,4 @@
1
- import { G as JwksTokenVerifier, A as AuthyonServerClient } from './authyonServerClient-DmNnjw4z.js';
1
+ import { K as JwksTokenVerifier, A as AuthyonServerClient } from './authyonServerClient-1_1qNRDa.js';
2
2
 
3
3
  type AbilitySubject = string | Record<string, unknown>;
4
4
  type AbilityConditions = Record<string, unknown>;
@@ -1,4 +1,4 @@
1
- import { G as JwksTokenVerifier, A as AuthyonServerClient } from './authyonServerClient-DmNnjw4z.cjs';
1
+ import { K as JwksTokenVerifier, A as AuthyonServerClient } from './authyonServerClient-1_1qNRDa.cjs';
2
2
 
3
3
  type AbilitySubject = string | Record<string, unknown>;
4
4
  type AbilityConditions = Record<string, unknown>;