@authyon/auth 0.1.5 → 0.2.0-beta.0
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 +158 -158
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,158 +1,158 @@
|
|
|
1
|
-
# @authyon/auth
|
|
2
|
-
|
|
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
|
-
|
|
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.
|
|
6
|
-
|
|
7
|
-
Para gestão de organização/membros (secret key) e verificação de token no backend, veja [`@authyon/server`](../server).
|
|
8
|
-
|
|
9
|
-
## Instalação
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
npm install @authyon/auth
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## Uso rápido
|
|
16
|
-
|
|
17
|
-
```ts
|
|
18
|
-
import { createClient } from "@authyon/auth";
|
|
19
|
-
|
|
20
|
-
const authyon = createClient({ envKey: "pk_live_..." });
|
|
21
|
-
|
|
22
|
-
// Login (com suporte a 2FA)
|
|
23
|
-
const result = await authyon.login({
|
|
24
|
-
email: "alice@acme.com",
|
|
25
|
-
password: "...",
|
|
26
|
-
organizationSlug: "acme", // opcional
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
if (result.twoFactorRequired) {
|
|
30
|
-
const code = prompt(`Código 2FA (${result.methods.join(", ")})`);
|
|
31
|
-
await authyon.verifyTwoFactor({
|
|
32
|
-
challengeToken: result.challengeToken,
|
|
33
|
-
method: "authenticator",
|
|
34
|
-
code: code!,
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Usuário atual — o access token é renovado automaticamente quando necessário
|
|
39
|
-
const user = await authyon.user.me();
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## Sessão e tokens
|
|
43
|
-
|
|
44
|
-
- Tokens persistem em `localStorage` por padrão (`memoryStorage()` ou um `TokenStorage` próprio via opção `storage`).
|
|
45
|
-
- `getAccessToken()` renova o token automaticamente antes de expirar (refresh token é single-use e rotacionado, com single-flight para evitar corridas).
|
|
46
|
-
- Chamadas autenticadas que retornam 401 fazem um refresh e uma retentativa automática.
|
|
47
|
-
|
|
48
|
-
```ts
|
|
49
|
-
const token = await authyon.getAccessToken(); // sempre válido, ou null se deslogado
|
|
50
|
-
|
|
51
|
-
const unsubscribe = authyon.onAuthStateChange((event) => {
|
|
52
|
-
// "signed_in" | "refreshed" | "signed_out"
|
|
53
|
-
console.log(event.type);
|
|
54
|
-
});
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
## API
|
|
58
|
-
|
|
59
|
-
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
|
-
|
|
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` |
|
|
70
|
-
|
|
71
|
-
### `authyon.user`
|
|
72
|
-
|
|
73
|
-
| Método | Endpoint |
|
|
74
|
-
| ----------------------------------------------- | ----------------------------------- |
|
|
75
|
-
| `user.me()` | `GET /auth/me` |
|
|
76
|
-
| `user.sessions()` | `GET /auth/sessions` |
|
|
77
|
-
| `user.revokeSession(sessionId)` | `DELETE /auth/sessions/{id}` |
|
|
78
|
-
| `user.activities(params?)` | `GET /auth/me/activities` |
|
|
79
|
-
| `user.requestPasswordReset(email)` | `POST /auth/password-reset/request` |
|
|
80
|
-
| `user.confirmPasswordReset(token, newPassword)` | `POST /auth/password-reset/confirm` |
|
|
81
|
-
|
|
82
|
-
### `authyon.organization`
|
|
83
|
-
|
|
84
|
-
| Método | Endpoint |
|
|
85
|
-
| ----------------------------------------------------- | ---------------------------------------------- |
|
|
86
|
-
| `organization.list()` | `GET /auth/tenants` |
|
|
87
|
-
| `organization.create(params?)` | `POST /auth/tenants` |
|
|
88
|
-
| `organization.get(organizationId)` | `GET /auth/tenants/{id}` |
|
|
89
|
-
| `organization.rename(organizationId, name)` | `PATCH /auth/tenants/{id}` |
|
|
90
|
-
| `organization.switch(slug)` | `POST /auth/switch-tenant` |
|
|
91
|
-
| `organization.current()` | — (lê `activeOrganization` da sessão em cache) |
|
|
92
|
-
| `organization.members.list(organizationId, params?)` | `GET /auth/tenants/{id}/members` |
|
|
93
|
-
| `organization.members.invite(organizationId, params)` | `POST /auth/tenants/{id}/members` |
|
|
94
|
-
| `organization.members.remove(organizationId, userId)` | `DELETE /auth/tenants/{id}/members/{userId}` |
|
|
95
|
-
| `organization.roles.list(organizationId)` | `GET /auth/tenants/{id}/roles` |
|
|
96
|
-
|
|
97
|
-
### `authyon.twoFactor`
|
|
98
|
-
|
|
99
|
-
| Método | Endpoint |
|
|
100
|
-
| ---------------------------------------------------- | -------------------------------------------- |
|
|
101
|
-
| `twoFactor.status()` | `GET /auth/2fa/status` |
|
|
102
|
-
| `twoFactor.resendEmail(challengeToken)` | `POST /auth/2fa/resend-email` |
|
|
103
|
-
| `twoFactor.setupAuthenticator()` | `POST /auth/2fa/authenticator/setup` |
|
|
104
|
-
| `twoFactor.confirmAuthenticator(code)` | `POST /auth/2fa/authenticator/confirm` |
|
|
105
|
-
| `twoFactor.enableEmail(code?)` | `POST /auth/2fa/email/enable` |
|
|
106
|
-
| `twoFactor.disable(method, currentPassword)` | `POST /auth/2fa/disable` |
|
|
107
|
-
| `twoFactor.regenerateRecoveryCodes(currentPassword)` | `POST /auth/2fa/recovery-codes/regenerate` |
|
|
108
|
-
| `twoFactor.webauthn.registerStart()` | `POST /auth/2fa/webauthn/register/start` |
|
|
109
|
-
| `twoFactor.webauthn.registerFinish(...)` | `POST /auth/2fa/webauthn/register/finish` |
|
|
110
|
-
| `twoFactor.webauthn.credentials()` | `GET /auth/2fa/webauthn/credentials` |
|
|
111
|
-
| `twoFactor.webauthn.renameCredential(id, nickname)` | `PATCH /auth/2fa/webauthn/credentials/{id}` |
|
|
112
|
-
| `twoFactor.webauthn.removeCredential(id, pwd)` | `DELETE /auth/2fa/webauthn/credentials/{id}` |
|
|
113
|
-
| `twoFactor.webauthn.assertionStart(challengeToken)` | `POST /auth/2fa/webauthn/assertion/start` |
|
|
114
|
-
|
|
115
|
-
### `authyon.webauthn` (login sem senha)
|
|
116
|
-
|
|
117
|
-
| Método | Endpoint |
|
|
118
|
-
| --------------------------------- | ---------------------------------- |
|
|
119
|
-
| `webauthn.loginStart(email?)` | `POST /auth/webauthn/login/start` |
|
|
120
|
-
| `webauthn.loginFinish(assertion)` | `POST /auth/webauthn/login/finish` |
|
|
121
|
-
|
|
122
|
-
### `authyon.sso` (login social)
|
|
123
|
-
|
|
124
|
-
| Método | Endpoint |
|
|
125
|
-
| -------------------------------- | ------------------------------------------------------------------------------------- |
|
|
126
|
-
| `sso.providers()` | `GET /auth/sso/providers` |
|
|
127
|
-
| `sso.startUrl(provider, params)` | monta a URL de `GET /auth/sso/{provider}/start` (não faz a chamada — navegue até ela) |
|
|
128
|
-
| `sso.exchange(code)` | `POST /auth/sso/exchange` |
|
|
129
|
-
|
|
130
|
-
## Invalidação de token
|
|
131
|
-
|
|
132
|
-
- **Sessão atual**: `logout()` revoga o refresh token atual; `logout({ everywhere: true })` revoga todos os refresh tokens do usuário.
|
|
133
|
-
- **Uma sessão específica**: `user.revokeSession(sessionId)`, usando o `id` retornado por `user.sessions()` — derruba um dispositivo sem afetar a sessão atual.
|
|
134
|
-
- **Access token**: por ser um JWT stateless, o access token continua "válido" até expirar (`expiresIn`, tipicamente 30 min) mesmo após revogar o refresh token. Para checar revogação em tempo real no seu backend, use `validate()` (cross-checa o estado no banco) em vez de `introspect()`.
|
|
135
|
-
|
|
136
|
-
## Erros
|
|
137
|
-
|
|
138
|
-
Toda resposta não-2xx vira um `AuthyonError` (problem+json). Compare pelo `code` legível por máquina, nunca pelo `title`:
|
|
139
|
-
|
|
140
|
-
```ts
|
|
141
|
-
import { AuthyonError, ErrorCodes } from "@authyon/auth";
|
|
142
|
-
|
|
143
|
-
try {
|
|
144
|
-
await authyon.register({ email, password });
|
|
145
|
-
} catch (err) {
|
|
146
|
-
if (err instanceof AuthyonError && err.is(ErrorCodes.EmailTaken)) {
|
|
147
|
-
// e-mail já cadastrado
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
## Build
|
|
153
|
-
|
|
154
|
-
```bash
|
|
155
|
-
npm install
|
|
156
|
-
npm run build # dist/ (ESM + CJS + .d.ts via tsup)
|
|
157
|
-
npm run typecheck
|
|
158
|
-
```
|
|
1
|
+
# @authyon/auth
|
|
2
|
+
|
|
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
|
+
|
|
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.
|
|
6
|
+
|
|
7
|
+
Para gestão de organização/membros (secret key) e verificação de token no backend, veja [`@authyon/server`](../server).
|
|
8
|
+
|
|
9
|
+
## Instalação
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @authyon/auth
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Uso rápido
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { createClient } from "@authyon/auth";
|
|
19
|
+
|
|
20
|
+
const authyon = createClient({ envKey: "pk_live_..." });
|
|
21
|
+
|
|
22
|
+
// Login (com suporte a 2FA)
|
|
23
|
+
const result = await authyon.login({
|
|
24
|
+
email: "alice@acme.com",
|
|
25
|
+
password: "...",
|
|
26
|
+
organizationSlug: "acme", // opcional
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
if (result.twoFactorRequired) {
|
|
30
|
+
const code = prompt(`Código 2FA (${result.methods.join(", ")})`);
|
|
31
|
+
await authyon.verifyTwoFactor({
|
|
32
|
+
challengeToken: result.challengeToken,
|
|
33
|
+
method: "authenticator",
|
|
34
|
+
code: code!,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Usuário atual — o access token é renovado automaticamente quando necessário
|
|
39
|
+
const user = await authyon.user.me();
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Sessão e tokens
|
|
43
|
+
|
|
44
|
+
- Tokens persistem em `localStorage` por padrão (`memoryStorage()` ou um `TokenStorage` próprio via opção `storage`).
|
|
45
|
+
- `getAccessToken()` renova o token automaticamente antes de expirar (refresh token é single-use e rotacionado, com single-flight para evitar corridas).
|
|
46
|
+
- Chamadas autenticadas que retornam 401 fazem um refresh e uma retentativa automática.
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
const token = await authyon.getAccessToken(); // sempre válido, ou null se deslogado
|
|
50
|
+
|
|
51
|
+
const unsubscribe = authyon.onAuthStateChange((event) => {
|
|
52
|
+
// "signed_in" | "refreshed" | "signed_out"
|
|
53
|
+
console.log(event.type);
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## API
|
|
58
|
+
|
|
59
|
+
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
|
+
|
|
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` |
|
|
70
|
+
|
|
71
|
+
### `authyon.user`
|
|
72
|
+
|
|
73
|
+
| Método | Endpoint |
|
|
74
|
+
| ----------------------------------------------- | ----------------------------------- |
|
|
75
|
+
| `user.me()` | `GET /auth/me` |
|
|
76
|
+
| `user.sessions()` | `GET /auth/sessions` |
|
|
77
|
+
| `user.revokeSession(sessionId)` | `DELETE /auth/sessions/{id}` |
|
|
78
|
+
| `user.activities(params?)` | `GET /auth/me/activities` |
|
|
79
|
+
| `user.requestPasswordReset(email)` | `POST /auth/password-reset/request` |
|
|
80
|
+
| `user.confirmPasswordReset(token, newPassword)` | `POST /auth/password-reset/confirm` |
|
|
81
|
+
|
|
82
|
+
### `authyon.organization`
|
|
83
|
+
|
|
84
|
+
| Método | Endpoint |
|
|
85
|
+
| ----------------------------------------------------- | ---------------------------------------------- |
|
|
86
|
+
| `organization.list()` | `GET /auth/tenants` |
|
|
87
|
+
| `organization.create(params?)` | `POST /auth/tenants` |
|
|
88
|
+
| `organization.get(organizationId)` | `GET /auth/tenants/{id}` |
|
|
89
|
+
| `organization.rename(organizationId, name)` | `PATCH /auth/tenants/{id}` |
|
|
90
|
+
| `organization.switch(slug)` | `POST /auth/switch-tenant` |
|
|
91
|
+
| `organization.current()` | — (lê `activeOrganization` da sessão em cache) |
|
|
92
|
+
| `organization.members.list(organizationId, params?)` | `GET /auth/tenants/{id}/members` |
|
|
93
|
+
| `organization.members.invite(organizationId, params)` | `POST /auth/tenants/{id}/members` |
|
|
94
|
+
| `organization.members.remove(organizationId, userId)` | `DELETE /auth/tenants/{id}/members/{userId}` |
|
|
95
|
+
| `organization.roles.list(organizationId)` | `GET /auth/tenants/{id}/roles` |
|
|
96
|
+
|
|
97
|
+
### `authyon.twoFactor`
|
|
98
|
+
|
|
99
|
+
| Método | Endpoint |
|
|
100
|
+
| ---------------------------------------------------- | -------------------------------------------- |
|
|
101
|
+
| `twoFactor.status()` | `GET /auth/2fa/status` |
|
|
102
|
+
| `twoFactor.resendEmail(challengeToken)` | `POST /auth/2fa/resend-email` |
|
|
103
|
+
| `twoFactor.setupAuthenticator()` | `POST /auth/2fa/authenticator/setup` |
|
|
104
|
+
| `twoFactor.confirmAuthenticator(code)` | `POST /auth/2fa/authenticator/confirm` |
|
|
105
|
+
| `twoFactor.enableEmail(code?)` | `POST /auth/2fa/email/enable` |
|
|
106
|
+
| `twoFactor.disable(method, currentPassword)` | `POST /auth/2fa/disable` |
|
|
107
|
+
| `twoFactor.regenerateRecoveryCodes(currentPassword)` | `POST /auth/2fa/recovery-codes/regenerate` |
|
|
108
|
+
| `twoFactor.webauthn.registerStart()` | `POST /auth/2fa/webauthn/register/start` |
|
|
109
|
+
| `twoFactor.webauthn.registerFinish(...)` | `POST /auth/2fa/webauthn/register/finish` |
|
|
110
|
+
| `twoFactor.webauthn.credentials()` | `GET /auth/2fa/webauthn/credentials` |
|
|
111
|
+
| `twoFactor.webauthn.renameCredential(id, nickname)` | `PATCH /auth/2fa/webauthn/credentials/{id}` |
|
|
112
|
+
| `twoFactor.webauthn.removeCredential(id, pwd)` | `DELETE /auth/2fa/webauthn/credentials/{id}` |
|
|
113
|
+
| `twoFactor.webauthn.assertionStart(challengeToken)` | `POST /auth/2fa/webauthn/assertion/start` |
|
|
114
|
+
|
|
115
|
+
### `authyon.webauthn` (login sem senha)
|
|
116
|
+
|
|
117
|
+
| Método | Endpoint |
|
|
118
|
+
| --------------------------------- | ---------------------------------- |
|
|
119
|
+
| `webauthn.loginStart(email?)` | `POST /auth/webauthn/login/start` |
|
|
120
|
+
| `webauthn.loginFinish(assertion)` | `POST /auth/webauthn/login/finish` |
|
|
121
|
+
|
|
122
|
+
### `authyon.sso` (login social)
|
|
123
|
+
|
|
124
|
+
| Método | Endpoint |
|
|
125
|
+
| -------------------------------- | ------------------------------------------------------------------------------------- |
|
|
126
|
+
| `sso.providers()` | `GET /auth/sso/providers` |
|
|
127
|
+
| `sso.startUrl(provider, params)` | monta a URL de `GET /auth/sso/{provider}/start` (não faz a chamada — navegue até ela) |
|
|
128
|
+
| `sso.exchange(code)` | `POST /auth/sso/exchange` |
|
|
129
|
+
|
|
130
|
+
## Invalidação de token
|
|
131
|
+
|
|
132
|
+
- **Sessão atual**: `logout()` revoga o refresh token atual; `logout({ everywhere: true })` revoga todos os refresh tokens do usuário.
|
|
133
|
+
- **Uma sessão específica**: `user.revokeSession(sessionId)`, usando o `id` retornado por `user.sessions()` — derruba um dispositivo sem afetar a sessão atual.
|
|
134
|
+
- **Access token**: por ser um JWT stateless, o access token continua "válido" até expirar (`expiresIn`, tipicamente 30 min) mesmo após revogar o refresh token. Para checar revogação em tempo real no seu backend, use `validate()` (cross-checa o estado no banco) em vez de `introspect()`.
|
|
135
|
+
|
|
136
|
+
## Erros
|
|
137
|
+
|
|
138
|
+
Toda resposta não-2xx vira um `AuthyonError` (problem+json). Compare pelo `code` legível por máquina, nunca pelo `title`:
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
import { AuthyonError, ErrorCodes } from "@authyon/auth";
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
await authyon.register({ email, password });
|
|
145
|
+
} catch (err) {
|
|
146
|
+
if (err instanceof AuthyonError && err.is(ErrorCodes.EmailTaken)) {
|
|
147
|
+
// e-mail já cadastrado
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Build
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
npm install
|
|
156
|
+
npm run build # dist/ (ESM + CJS + .d.ts via tsup)
|
|
157
|
+
npm run typecheck
|
|
158
|
+
```
|