@authyon/auth 0.2.0-beta.0 → 0.2.0-beta.2

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 MutualPay
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -2,22 +2,24 @@
2
2
 
3
3
  SDK JS/TS para o [Authyon](https://authyon.com) — autenticação, sessões, multi-tenant e 2FA, com armazenamento e refresh de tokens transparentes.
4
4
 
5
- Cobre todos os endpoints públicos documentados em [authyon.com/docs](https://authyon.com/docs), usando a **publishable key** (`pk_...`) — segura para expor no navegador.
5
+ Cobre os endpoints públicos do Authyon usando a **publishable key** (`pk_...`) — segura para identificar o ambiente no navegador, sem conceder privilégios administrativos.
6
6
 
7
- Para gestão de organização/membros (secret key) e verificação de token no backend, veja [`@authyon/server`](../server).
7
+ Para gestão de organização/membros (secret key) e verificação de token no backend, use `@authyon/server`.
8
8
 
9
9
  ## Instalação
10
10
 
11
11
  ```bash
12
- npm install @authyon/auth
12
+ npm install --save-exact @authyon/auth@0.2.0-beta.1
13
13
  ```
14
14
 
15
+ Durante a beta, `npm install @authyon/auth@beta` acompanha o prerelease mais recente. Fixar a versão exata é recomendado para builds reproduzíveis.
16
+
15
17
  ## Uso rápido
16
18
 
17
19
  ```ts
18
20
  import { createClient } from "@authyon/auth";
19
21
 
20
- const authyon = createClient({ envKey: "pk_live_..." });
22
+ const authyon = createClient({ envKey: "pk_live_..." }); // tokens somente em memória por padrão
21
23
 
22
24
  // Login (com suporte a 2FA)
23
25
  const result = await authyon.login({
@@ -39,13 +41,67 @@ if (result.twoFactorRequired) {
39
41
  const user = await authyon.user.me();
40
42
  ```
41
43
 
44
+ ## Next.js e React
45
+
46
+ Use o entrypoint dedicado `@authyon/auth/react`:
47
+
48
+ ```tsx
49
+ <AuthyonProvider client={authyon}>
50
+ <SessionGuard loadingFallback={<Loading />}>
51
+ <PermissionGuard action="read" subject="reports">
52
+ <Reports />
53
+ </PermissionGuard>
54
+ </SessionGuard>
55
+ </AuthyonProvider>
56
+ ```
57
+
58
+ O provider faz refresh automático, valida a sessão por `GET /auth/me`, atualiza usuário e permissions, revalida quando a aba volta ao foco e não libera guards enquanto a validação inicial estiver pendente. Use `useAuthyon()`, `useAuthyonAbility()` e `useCan()` para fluxos programáticos.
59
+
60
+ Use `transformUser` para expor campos derivados sem alterar a sessão mantida pela lib:
61
+
62
+ ```tsx
63
+ type ApplicationUser = User & { fullName: string };
64
+
65
+ <AuthyonProvider<ApplicationUser>
66
+ client={authyon}
67
+ transformUser={(user) => ({
68
+ ...user,
69
+ fullName: [user.firstName, user.lastName].filter(Boolean).join(" "),
70
+ })}
71
+ >
72
+ <App />
73
+ </AuthyonProvider>;
74
+
75
+ const { user, session } = useAuthyon<ApplicationUser>();
76
+ ```
77
+
78
+ O usuário transformado é retornado em `user` e em `session.user` após validação, refresh, login e troca de organização. O transformador deve ser puro e só derivar dados do perfil do Authyon; dados externos pertencem ao contexto da aplicação.
79
+
80
+ Para configuração progressiva, use o builder:
81
+
82
+ ```ts
83
+ const authyon = new AuthyonClientBuilder("pk_live_...")
84
+ .withStorage(createMemoryStorage())
85
+ .withTimeout(10_000)
86
+ .build();
87
+ ```
88
+
42
89
  ## Sessão e tokens
43
90
 
44
- - Tokens persistem em `localStorage` por padrão (`memoryStorage()` ou um `TokenStorage` próprio via opção `storage`).
91
+ - Tokens ficam somente em memória por padrão, reduzindo o impacto de XSS e sendo removidos ao recarregar a página.
92
+ - Persistência é opt-in com `storage: createLocalStorage()`. Isso melhora conveniência, mas qualquer XSS na aplicação poderá ler os tokens; criptografar o valor não elimina esse risco porque o JavaScript também precisa acessar a chave.
45
93
  - `getAccessToken()` renova o token automaticamente antes de expirar (refresh token é single-use e rotacionado, com single-flight para evitar corridas).
46
94
  - Chamadas autenticadas que retornam 401 fazem um refresh e uma retentativa automática.
47
95
 
48
96
  ```ts
97
+ import { createClient, createLocalStorage } from "@authyon/auth";
98
+
99
+ // Use somente quando a persistência for um requisito aceito conscientemente.
100
+ const persistentClient = createClient({
101
+ envKey: "pk_live_...",
102
+ storage: createLocalStorage(),
103
+ });
104
+
49
105
  const token = await authyon.getAccessToken(); // sempre válido, ou null se deslogado
50
106
 
51
107
  const unsubscribe = authyon.onAuthStateChange((event) => {
@@ -54,19 +110,109 @@ const unsubscribe = authyon.onAuthStateChange((event) => {
54
110
  });
55
111
  ```
56
112
 
113
+ Para aplicações de maior risco, prefira um BFF que mantenha o refresh token em cookie `HttpOnly`, `Secure` e `SameSite`, com proteção CSRF. O SDK também exige HTTPS para APIs remotas e aplica timeout de 15 segundos por padrão (`timeoutMs: 0` desabilita).
114
+
115
+ ## HTTP Adapter
116
+
117
+ Use `httpAdapter` para integrar mocks, tracing ou outra biblioteca HTTP. O mesmo contrato está disponível em `@authyon/auth` e `@authyon/server`:
118
+
119
+ ```ts
120
+ import { createClient, type HttpAdapter } from "@authyon/auth";
121
+
122
+ const httpAdapter: HttpAdapter = {
123
+ async request(request) {
124
+ // tracing, métricas ou adaptação para sua stack HTTP
125
+ return fetch(request.url, {
126
+ method: request.method,
127
+ headers: request.headers,
128
+ body: request.body,
129
+ signal: request.signal,
130
+ });
131
+ },
132
+ };
133
+
134
+ const authyon = createClient({ envKey: "pk_live_...", httpAdapter });
135
+ ```
136
+
137
+ `FetchHttpAdapter` é a implementação padrão e também pode encapsular um `fetch` customizado. Não configure `httpAdapter` e `fetch` ao mesmo tempo.
138
+
139
+ O logger HTTP é desabilitado por padrão. Passe uma configuração mutável para observar e manipular eventos de request, response e erro; altere `enabled` a qualquer momento sem recriar o client:
140
+
141
+ ```ts
142
+ import { createClient, type HttpLoggerOptions } from "@authyon/auth";
143
+
144
+ const httpLogger: HttpLoggerOptions = {
145
+ enabled: true,
146
+ logger(event) {
147
+ observability.track(event.type, event);
148
+ },
149
+ };
150
+
151
+ const authyon = createClient({ envKey: "pk_live_...", httpLogger });
152
+
153
+ httpLogger.enabled = false; // desabilita
154
+ httpLogger.enabled = true; // habilita novamente
155
+ ```
156
+
157
+ Sem um `logger` customizado, os eventos usam `console.debug`. Headers, bodies e valores de query string são removidos dos eventos para evitar vazamento de tokens, senhas e dados pessoais. Falhas do logger são isoladas e não interrompem a autenticação. Para decorar um adapter manualmente, use `LoggingHttpAdapter`.
158
+
57
159
  ## API
58
160
 
161
+ ## Autorização baseada em permissões
162
+
163
+ Crie uma ability diretamente do usuário da sessão. Permissões Authyon seguem `subject:action`, por exemplo `tickets:read` e `documents:update`:
164
+
165
+ ```ts
166
+ import { createAuthyonAbility } from "@authyon/auth";
167
+
168
+ const ability = createAuthyonAbility(session.user, {
169
+ rules: [
170
+ {
171
+ action: "update",
172
+ subject: "documents",
173
+ inverted: true,
174
+ conditions: { locked: true },
175
+ reason: "Documento bloqueado",
176
+ },
177
+ ],
178
+ });
179
+
180
+ ability.can("read", "tickets");
181
+ ability.can("update", { __type: "documents", locked: false });
182
+ ability.cannot("update", { __type: "documents", locked: true });
183
+ ```
184
+
185
+ Também estão disponíveis `AuthyonAbilityBuilder`, regras por role, campos, condições com operadores (`$eq`, `$ne`, `$in`, `$nin`, `$gt`, `$gte`, `$lt`, `$lte`, `$exists`, `$and`, `$or`), `rulesFor()`, `update()` e o evento `updated`. A autorização é local e nega por padrão; o backend continua responsável por validar toda ação sensível.
186
+
187
+ ### Next.js Client Side
188
+
189
+ `@authyon/auth` e o motor de abilities são isomórficos e podem ser usados em Client Components:
190
+
191
+ ```tsx
192
+ "use client";
193
+
194
+ import { createAuthyonAbility } from "@authyon/auth";
195
+
196
+ export function EditButton({ user, document }) {
197
+ const ability = createAuthyonAbility(user);
198
+ if (ability.cannot("update", { __type: "documents", ...document })) return null;
199
+ return <button>Editar</button>;
200
+ }
201
+ ```
202
+
203
+ Essa verificação controla a interface, não a segurança do backend. Nunca importe `@authyon/server` em Client Components nem envie `clientSecret` ao navegador.
204
+
59
205
  Métodos de sessão/auth ficam soltos no client; os que giram em torno de um recurso específico ficam agrupados em namespaces (`user`, `organization`, `twoFactor`, `webauthn`, `sso`).
60
206
 
61
- | Método | Endpoint |
62
- | ------------------------------------------------------------------------ | ----------------------- |
63
- | `register({ email, username, password })` | `POST /auth/register` |
64
- | `login({ email \| username, password, organizationSlug? })` | `POST /auth/login` |
65
- | `verifyTwoFactor({ challengeToken, method, code?, webAuthnAssertion? })` | `POST /auth/2fa/verify` |
66
- | `refresh()` | `POST /auth/refresh` |
67
- | `logout({ everywhere? })` | `POST /auth/logout` |
68
- | `introspect(token?)` | `POST /auth/introspect` |
69
- | `validate(token?)` | `POST /auth/validate` |
207
+ | Método | Endpoint |
208
+ | ------------------------------------------------------------------------ | --------------------------------- |
209
+ | `register({ email, username, password })` | `POST /auth/register` |
210
+ | `login({ email \| username, password, organizationSlug? })` | `POST /auth/login` |
211
+ | `verifyTwoFactor({ challengeToken, method, code?, webAuthnAssertion? })` | `POST /auth/2fa/verify` |
212
+ | `refresh()` | `POST /auth/refresh` |
213
+ | `logout({ everywhere? })` | `POST /auth/logout` |
214
+ | `introspect(token?)` | Deprecated: use `@authyon/server` |
215
+ | `validate(token?)` | Deprecated: use `@authyon/server` |
70
216
 
71
217
  ### `authyon.user`
72
218
 
@@ -137,6 +283,23 @@ Métodos de sessão/auth ficam soltos no client; os que giram em torno de um rec
137
283
 
138
284
  Toda resposta não-2xx vira um `AuthyonError` (problem+json). Compare pelo `code` legível por máquina, nunca pelo `title`:
139
285
 
286
+ Falhas de transporte usam `request.network_error` ou `request.timeout`. Quando presentes, `requestId` e `retryAfter` ajudam suporte e tratamento de rate limit sem expor o corpo da requisição.
287
+
288
+ `interpret()` converte códigos e status em uma decisão estável para a interface:
289
+
290
+ ```ts
291
+ try {
292
+ await authyon.login({ email, password });
293
+ } catch (cause) {
294
+ if (!(cause instanceof AuthyonError)) throw cause;
295
+ const { category, action, retryable, retryAfter } = cause.interpret();
296
+ // category: authentication | validation | rate_limit | network | ...
297
+ // action: reauthenticate | fix_input | retry | ...
298
+ }
299
+ ```
300
+
301
+ Veja o catálogo completo em `ERRORS.md` no repositório.
302
+
140
303
  ```ts
141
304
  import { AuthyonError, ErrorCodes } from "@authyon/auth";
142
305