@adonis-agora/authkit-server 0.56.0 → 0.57.1
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 +4 -4
- package/build/index.d.ts +1 -1
- package/build/index.js +1 -1
- package/build/src/define_config.d.ts +35 -8
- package/build/src/doctor/checks.d.ts +5 -3
- package/build/src/doctor/checks.js +5 -3
- package/build/src/host/config_locks.js +1 -1
- package/build/src/host/impersonation_session.d.ts +22 -2
- package/build/src/host/impersonation_session.js +70 -3
- package/build/src/host/register_auth_host.d.ts +27 -6
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ node ace add @adonis-agora/authkit-server
|
|
|
31
31
|
# ou: pnpm add @adonis-agora/authkit-server && node ace configure @adonis-agora/authkit-server
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
O `configure` publica `config/
|
|
34
|
+
O `configure` publica `config/authkit.ts`, o model `app/models/auth_user.ts`,
|
|
35
35
|
o controller de interactions (`app/controllers/auth_interaction_controller.ts`) e
|
|
36
36
|
registra o provider.
|
|
37
37
|
|
|
@@ -89,7 +89,7 @@ Em todos os presets o controller ejetado é **casca**: a lógica vive em
|
|
|
89
89
|
`details(ctx)`, `login(ctx, { email, password })` e `consent(ctx)`. Você edita só a parte de
|
|
90
90
|
render/redirect.
|
|
91
91
|
|
|
92
|
-
Quem decide se as credenciais valem é o `verifyCredentials` do `config/
|
|
92
|
+
Quem decide se as credenciais valem é o `verifyCredentials` do `config/authkit.ts`
|
|
93
93
|
— é o que o `service.interactions.login` chama. O default consulta o `AuthUser` por e-mail e
|
|
94
94
|
usa `verifyPassword`; sobrescreva para plugar sua própria base de usuários.
|
|
95
95
|
|
|
@@ -105,7 +105,7 @@ router.post('/auth/interaction/:uid/consent', [AuthInteractionController, 'conse
|
|
|
105
105
|
|
|
106
106
|
## Persistência
|
|
107
107
|
|
|
108
|
-
Escolha o backend no `config/
|
|
108
|
+
Escolha o backend no `config/authkit.ts`:
|
|
109
109
|
- `adapters.redis({ connection })` — requer `@adonisjs/redis` configurado.
|
|
110
110
|
- `adapters.database({ connection? })` — Lucid; rode a migração `authkit_oidc_payloads`.
|
|
111
111
|
|
|
@@ -116,7 +116,7 @@ de resolve) e as expõe de forma opt-in.
|
|
|
116
116
|
|
|
117
117
|
### Configuração
|
|
118
118
|
|
|
119
|
-
No `config/
|
|
119
|
+
No `config/authkit.ts`, use a chave `observability`:
|
|
120
120
|
|
|
121
121
|
```ts
|
|
122
122
|
observability: {
|
package/build/index.d.ts
CHANGED
|
@@ -129,7 +129,7 @@ export { resolveRegistration } from './src/define_config.js';
|
|
|
129
129
|
export type { RegistrationConfigInput, ResolvedRegistrationConfig, } from './src/define_config.js';
|
|
130
130
|
export { getAccountId, realAccountId, hasAccountSession, consoleLoginUrl, } from './src/host/console_session.js';
|
|
131
131
|
export { ACCOUNT_SESSION_KEY } from './src/host/middleware/account_auth.js';
|
|
132
|
-
export { rememberAccessToken, startImpersonation, impersonationState, stopImpersonation, } from './src/host/impersonation_session.js';
|
|
132
|
+
export { rememberAccessToken, rememberRefreshToken, refreshAccessToken, startImpersonation, impersonationState, stopImpersonation, } from './src/host/impersonation_session.js';
|
|
133
133
|
export type { StartImpersonationParams, ImpersonationState, } from './src/host/impersonation_session.js';
|
|
134
134
|
export { SUDO_SESSION_KEY, SUDO_ACCOUNT_SESSION_KEY, SUDO_MODE_DEFAULTS, requireSudo, isSudoActive, markSudo, resolveEffectiveSudoMode, } from './src/host/sudo_mode.js';
|
|
135
135
|
export type { SudoModeSetting, ResolvedSudoModeSetting, } from './src/host/sudo_mode.js';
|
package/build/index.js
CHANGED
|
@@ -91,7 +91,7 @@ export { ACCOUNT_SESSION_KEY } from './src/host/middleware/account_auth.js';
|
|
|
91
91
|
// Session impersonation — RP-side glue that routes through the IdP's RFC 8693
|
|
92
92
|
// token-exchange (the IdP validates the admin role + audits). See
|
|
93
93
|
// src/host/impersonation_session.ts.
|
|
94
|
-
export { rememberAccessToken, startImpersonation, impersonationState, stopImpersonation, } from './src/host/impersonation_session.js';
|
|
94
|
+
export { rememberAccessToken, rememberRefreshToken, refreshAccessToken, startImpersonation, impersonationState, stopImpersonation, } from './src/host/impersonation_session.js';
|
|
95
95
|
// Sudo mode — helpers for host controllers that require step-up authentication.
|
|
96
96
|
export { SUDO_SESSION_KEY, SUDO_ACCOUNT_SESSION_KEY, SUDO_MODE_DEFAULTS, requireSudo, isSudoActive, markSudo, resolveEffectiveSudoMode, } from './src/host/sudo_mode.js';
|
|
97
97
|
// SPI de métodos de confirmação de identidade (sudo mode).
|
|
@@ -131,6 +131,19 @@ export interface MailHooks {
|
|
|
131
131
|
unlockUrl: string;
|
|
132
132
|
token: string;
|
|
133
133
|
}) => Promise<void>;
|
|
134
|
+
/**
|
|
135
|
+
* Disparado pelo `authkit:expire-scan` quando uma conta está prestes a ser
|
|
136
|
+
* desativada por inatividade. Substitui o e-mail default de aviso quando
|
|
137
|
+
* fornecido. Best-effort, fire-and-forget; deduplicado pela janela de
|
|
138
|
+
* `warnDays` da setting `account_expiration`, então cada conta recebe no
|
|
139
|
+
* máximo um aviso por janela.
|
|
140
|
+
*/
|
|
141
|
+
onAccountExpirationWarning?: (data: {
|
|
142
|
+
/** E-mail da conta que será desativada. */
|
|
143
|
+
email: string;
|
|
144
|
+
/** Dias restantes até a desativação. */
|
|
145
|
+
expiresInDays: number;
|
|
146
|
+
}) => Promise<void>;
|
|
134
147
|
/**
|
|
135
148
|
* Disparado após um evento de segurança (senha alterada, MFA habilitado/desabilitado,
|
|
136
149
|
* passkey adicionada/removida, e-mail alterado). Substitui o e-mail default quando
|
|
@@ -888,15 +901,21 @@ export interface AuthServerConfigInput {
|
|
|
888
901
|
*/
|
|
889
902
|
accessTokens?: AccessTokensConfig;
|
|
890
903
|
/**
|
|
891
|
-
* Console admin do IdP (B6). Default: desligado.
|
|
892
|
-
*
|
|
893
|
-
*
|
|
904
|
+
* Console admin do IdP (B6). Default: desligado.
|
|
905
|
+
*
|
|
906
|
+
* Declarar esta chave TRAVA o liga/desliga: `registerAuthHost(router, { admin })`
|
|
907
|
+
* passa a ser ignorado (ver `deriveLockedRouteOptions`). Não repita o
|
|
908
|
+
* `enabled` no `start/routes.ts` — no máximo passe `admin: { prefix }`, que é
|
|
909
|
+
* estrutural e continua valendo.
|
|
894
910
|
*/
|
|
895
911
|
admin?: AdminConfigInput;
|
|
896
912
|
/**
|
|
897
|
-
* Admin REST API (R6). Default: desligada.
|
|
898
|
-
*
|
|
899
|
-
*
|
|
913
|
+
* Admin REST API (R6). Default: desligada. Autenticação por API key.
|
|
914
|
+
*
|
|
915
|
+
* Declarar esta chave TRAVA o liga/desliga: `registerAuthHost(router, { adminApi })`
|
|
916
|
+
* passa a ser ignorado (ver `deriveLockedRouteOptions`). Não repita o
|
|
917
|
+
* `enabled` no `start/routes.ts` — no máximo passe `adminApi: { prefix }`, que
|
|
918
|
+
* é estrutural e continua valendo.
|
|
900
919
|
*/
|
|
901
920
|
adminApi?: AdminApiConfigInput;
|
|
902
921
|
/**
|
|
@@ -913,8 +932,16 @@ export interface AuthServerConfigInput {
|
|
|
913
932
|
*/
|
|
914
933
|
resolveGeo?: ResolveGeo;
|
|
915
934
|
/**
|
|
916
|
-
* Gestão automática do schema das tabelas do authkit
|
|
917
|
-
* `auth_settings`, `auth_password_history
|
|
935
|
+
* Gestão automática do schema das OITO tabelas do authkit:
|
|
936
|
+
* `authkit_oidc_payloads`, `auth_settings`, `auth_password_history`,
|
|
937
|
+
* `auth_mfa`, `auth_session_revocations` e as três de organizations
|
|
938
|
+
* (`auth_organizations`, `auth_organization_members`,
|
|
939
|
+
* `auth_organization_invitations`). Ver `TABLES` em `schema/ensure.ts` — a
|
|
940
|
+
* lista aqui existe para o leitor, mas quem manda é aquele array.
|
|
941
|
+
*
|
|
942
|
+
* FORA desta gestão: `authkit_keystore`, criada sob demanda pelo
|
|
943
|
+
* `LucidKeystoreVault` na primeira escrita, e as tabelas do MODEL do host
|
|
944
|
+
* (`auth_users` etc.), que são migrations do app.
|
|
918
945
|
*
|
|
919
946
|
* - `autoManage` (default `true`): no boot, cria as tabelas que faltam e
|
|
920
947
|
* adiciona colunas novas (aditivo — nunca dropa nem altera tipos).
|
|
@@ -138,9 +138,11 @@ export declare function checkEmailChange(input: DoctorInput): Finding | null;
|
|
|
138
138
|
*/
|
|
139
139
|
export declare function checkSecurityNotifications(input: DoctorInput): Finding | null;
|
|
140
140
|
/**
|
|
141
|
-
* Verifica
|
|
142
|
-
* -
|
|
143
|
-
* -
|
|
141
|
+
* Verifica o pepper de senha (`accountStore.password.pepper`).
|
|
142
|
+
* - Silencioso quando não há pepper configurado.
|
|
143
|
+
* - Reporta o pepper como string e sugere a forma `[novo, antigo]`, que permite
|
|
144
|
+
* rotação sem downtime (lazy re-hash no verify).
|
|
145
|
+
* - Reporta quantos peppers a rotação tem quando já é array.
|
|
144
146
|
*/
|
|
145
147
|
export declare function checkPasswordPepper(input: DoctorInput): Finding | null;
|
|
146
148
|
/**
|
|
@@ -573,9 +573,11 @@ export function checkSecurityNotifications(input) {
|
|
|
573
573
|
return null; // Silencioso quando tudo está ok (não-obrigatório).
|
|
574
574
|
}
|
|
575
575
|
/**
|
|
576
|
-
* Verifica
|
|
577
|
-
* -
|
|
578
|
-
* -
|
|
576
|
+
* Verifica o pepper de senha (`accountStore.password.pepper`).
|
|
577
|
+
* - Silencioso quando não há pepper configurado.
|
|
578
|
+
* - Reporta o pepper como string e sugere a forma `[novo, antigo]`, que permite
|
|
579
|
+
* rotação sem downtime (lazy re-hash no verify).
|
|
580
|
+
* - Reporta quantos peppers a rotação tem quando já é array.
|
|
579
581
|
*/
|
|
580
582
|
export function checkPasswordPepper(input) {
|
|
581
583
|
const store = input.authkitConfig?.accountStore;
|
|
@@ -94,7 +94,7 @@ export class SettingLockedError extends Error {
|
|
|
94
94
|
code = 'E_SETTING_LOCKED';
|
|
95
95
|
key;
|
|
96
96
|
constructor(key) {
|
|
97
|
-
super(`
|
|
97
|
+
super(`The setting "${key}" is declared in defineConfig() and is therefore locked — it cannot be changed at runtime through the console or the Admin API. Remove it from defineConfig to hand the key back to the UI.`);
|
|
98
98
|
this.name = 'SettingLockedError';
|
|
99
99
|
this.key = key;
|
|
100
100
|
}
|
|
@@ -4,10 +4,16 @@ import type { HttpContext } from '@adonisjs/core/http';
|
|
|
4
4
|
* após o login). Necessário porque o token-exchange exige o access token do admin
|
|
5
5
|
* como `subject_token`, e o RP normalmente descarta os tokens após o login.
|
|
6
6
|
*
|
|
7
|
-
* Access tokens são curtos: se expirar, `startImpersonation`
|
|
8
|
-
*
|
|
7
|
+
* Access tokens são curtos: se expirar, `startImpersonation` renova via refresh
|
|
8
|
+
* token (`rememberRefreshToken`) e tenta de novo — o admin não precisa relogar.
|
|
9
9
|
*/
|
|
10
10
|
export declare function rememberAccessToken(ctx: HttpContext, accessToken: string): void;
|
|
11
|
+
/**
|
|
12
|
+
* Guarda o refresh token do admin (do scope `offline_access`), usado para
|
|
13
|
+
* renovar o access token expirado antes do token-exchange. Chame no callback
|
|
14
|
+
* OIDC do RP junto com `rememberAccessToken`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function rememberRefreshToken(ctx: HttpContext, refreshToken: string): void;
|
|
11
17
|
export interface StartImpersonationParams {
|
|
12
18
|
/** Id do usuário-alvo a personificar. */
|
|
13
19
|
targetId: string;
|
|
@@ -27,6 +33,20 @@ export interface ImpersonationState {
|
|
|
27
33
|
/** O admin real (impersonator), quando `active`. */
|
|
28
34
|
impersonatorId?: string;
|
|
29
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Renova o access token do admin via refresh grant (RFC 6749 §6), usando o
|
|
38
|
+
* refresh token guardado por `rememberRefreshToken`. Retorna o novo access
|
|
39
|
+
* token (e o refresh token rotacionado, se o IdP emitir outro), ou null se não
|
|
40
|
+
* houver refresh token / o refresh falhar.
|
|
41
|
+
*
|
|
42
|
+
* O IdP deste pacote roda `refresh_token` grant por default
|
|
43
|
+
* (`build_provider.ts`: `grant_types: ['authorization_code', 'refresh_token']`),
|
|
44
|
+
* então o refresh é válido na configuração padrão.
|
|
45
|
+
*/
|
|
46
|
+
export declare function refreshAccessToken(ctx: HttpContext, params: Pick<StartImpersonationParams, 'issuer' | 'clientId' | 'clientSecret' | 'tokenEndpoint' | 'fetchImpl'>): Promise<{
|
|
47
|
+
accessToken: string;
|
|
48
|
+
refreshToken?: string;
|
|
49
|
+
} | null>;
|
|
30
50
|
/**
|
|
31
51
|
* Inicia a impersonation: lê o access token do admin da sessão, chama o
|
|
32
52
|
* token-exchange (o IdP valida a role admin e audita) e SÓ em sucesso guarda o
|
|
@@ -27,17 +27,32 @@ const IMPERSONATOR_SESSION_KEY = 'impersonator_user_id';
|
|
|
27
27
|
* `subject_token` do token-exchange. Interna: NÃO exporte o literal.
|
|
28
28
|
*/
|
|
29
29
|
const ADMIN_ACCESS_TOKEN_SESSION_KEY = 'admin_access_token';
|
|
30
|
+
/**
|
|
31
|
+
* Key de sessão que guarda o refresh token do admin (do `offline_access`),
|
|
32
|
+
* usado para renovar o access token expirado antes do token-exchange. Interna:
|
|
33
|
+
* NÃO exporte o literal.
|
|
34
|
+
*/
|
|
35
|
+
const ADMIN_REFRESH_TOKEN_SESSION_KEY = 'admin_refresh_token';
|
|
36
|
+
const REFRESH_TOKEN_GRANT = 'refresh_token';
|
|
30
37
|
/**
|
|
31
38
|
* Guarda o access token do admin na sessão (chame no callback OIDC do RP, logo
|
|
32
39
|
* após o login). Necessário porque o token-exchange exige o access token do admin
|
|
33
40
|
* como `subject_token`, e o RP normalmente descarta os tokens após o login.
|
|
34
41
|
*
|
|
35
|
-
* Access tokens são curtos: se expirar, `startImpersonation`
|
|
36
|
-
*
|
|
42
|
+
* Access tokens são curtos: se expirar, `startImpersonation` renova via refresh
|
|
43
|
+
* token (`rememberRefreshToken`) e tenta de novo — o admin não precisa relogar.
|
|
37
44
|
*/
|
|
38
45
|
export function rememberAccessToken(ctx, accessToken) {
|
|
39
46
|
ctx.session.put(ADMIN_ACCESS_TOKEN_SESSION_KEY, accessToken);
|
|
40
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Guarda o refresh token do admin (do scope `offline_access`), usado para
|
|
50
|
+
* renovar o access token expirado antes do token-exchange. Chame no callback
|
|
51
|
+
* OIDC do RP junto com `rememberAccessToken`.
|
|
52
|
+
*/
|
|
53
|
+
export function rememberRefreshToken(ctx, refreshToken) {
|
|
54
|
+
ctx.session.put(ADMIN_REFRESH_TOKEN_SESSION_KEY, refreshToken);
|
|
55
|
+
}
|
|
41
56
|
/**
|
|
42
57
|
* POST inline do RFC 8693 token-exchange. Inline (em vez de depender de
|
|
43
58
|
* `@adonis-agora/authkit-client`) porque o client NÃO é dependência do server e
|
|
@@ -68,6 +83,43 @@ async function requestTokenExchange(params, subjectToken) {
|
|
|
68
83
|
throw new Error(`Token exchange failed: ${res.status}`);
|
|
69
84
|
}
|
|
70
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Renova o access token do admin via refresh grant (RFC 6749 §6), usando o
|
|
88
|
+
* refresh token guardado por `rememberRefreshToken`. Retorna o novo access
|
|
89
|
+
* token (e o refresh token rotacionado, se o IdP emitir outro), ou null se não
|
|
90
|
+
* houver refresh token / o refresh falhar.
|
|
91
|
+
*
|
|
92
|
+
* O IdP deste pacote roda `refresh_token` grant por default
|
|
93
|
+
* (`build_provider.ts`: `grant_types: ['authorization_code', 'refresh_token']`),
|
|
94
|
+
* então o refresh é válido na configuração padrão.
|
|
95
|
+
*/
|
|
96
|
+
export async function refreshAccessToken(ctx, params) {
|
|
97
|
+
const refreshToken = ctx.session.get(ADMIN_REFRESH_TOKEN_SESSION_KEY);
|
|
98
|
+
if (!refreshToken)
|
|
99
|
+
return null;
|
|
100
|
+
const body = new URLSearchParams({
|
|
101
|
+
grant_type: REFRESH_TOKEN_GRANT,
|
|
102
|
+
refresh_token: refreshToken,
|
|
103
|
+
client_id: params.clientId,
|
|
104
|
+
});
|
|
105
|
+
if (params.clientSecret)
|
|
106
|
+
body.set('client_secret', params.clientSecret);
|
|
107
|
+
const fetchImpl = params.fetchImpl ?? fetch;
|
|
108
|
+
const res = await fetchImpl(params.tokenEndpoint ?? `${params.issuer}/token`, {
|
|
109
|
+
method: 'POST',
|
|
110
|
+
headers: { 'content-type': 'application/x-www-form-urlencoded' },
|
|
111
|
+
body: body.toString(),
|
|
112
|
+
});
|
|
113
|
+
if (!res.ok)
|
|
114
|
+
return null;
|
|
115
|
+
const data = (await res.json());
|
|
116
|
+
if (!data.access_token)
|
|
117
|
+
return null;
|
|
118
|
+
const result = { accessToken: data.access_token };
|
|
119
|
+
if (data.refresh_token)
|
|
120
|
+
result.refreshToken = data.refresh_token;
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
71
123
|
/**
|
|
72
124
|
* Inicia a impersonation: lê o access token do admin da sessão, chama o
|
|
73
125
|
* token-exchange (o IdP valida a role admin e audita) e SÓ em sucesso guarda o
|
|
@@ -94,7 +146,22 @@ export async function startImpersonation(ctx, params) {
|
|
|
94
146
|
}
|
|
95
147
|
// O IdP é o gatekeeper: lança se o admin não puder personificar. Chamado ANTES
|
|
96
148
|
// de qualquer mutação de sessão — em caso de erro nada é trocado.
|
|
97
|
-
|
|
149
|
+
try {
|
|
150
|
+
await requestTokenExchange(params, adminAccessToken);
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
// Access token expirado (4xx do exchange): renova via refresh token e tenta
|
|
154
|
+
// de novo. Sem refresh token / refresh falho → propaga o erro original.
|
|
155
|
+
if (!(err instanceof Error) || !/exchange failed: 4\d\d/.test(err.message))
|
|
156
|
+
throw err;
|
|
157
|
+
const refreshed = await refreshAccessToken(ctx, params);
|
|
158
|
+
if (!refreshed)
|
|
159
|
+
throw err;
|
|
160
|
+
rememberAccessToken(ctx, refreshed.accessToken);
|
|
161
|
+
if (refreshed.refreshToken)
|
|
162
|
+
rememberRefreshToken(ctx, refreshed.refreshToken);
|
|
163
|
+
await requestTokenExchange(params, refreshed.accessToken);
|
|
164
|
+
}
|
|
98
165
|
// Anti-fixation: rotaciona o id da sessão (mantém os dados) antes de gravar a
|
|
99
166
|
// nova identidade. Mesmo padrão do consumidor real no RP.
|
|
100
167
|
await ctx.session.regenerate();
|
|
@@ -39,14 +39,23 @@ export interface AuthHostOptions {
|
|
|
39
39
|
* Login social opt-in; quando presente, monta as rotas sociais (usam ctx.ally).
|
|
40
40
|
* Necessário aqui (e não só no config) porque a decisão de montar as rotas é
|
|
41
41
|
* tomada em tempo de registro, antes do config (lazy) resolver.
|
|
42
|
+
*
|
|
43
|
+
* POLÍTICA: se o `defineConfig` declarou `social`, ele vence e este argumento
|
|
44
|
+
* é IGNORADO (com `console.warn` + entrada em `overriddenByConfig`). NÃO
|
|
45
|
+
* espelhe o config aqui — omitir a chave já herda dele. Use este argumento só
|
|
46
|
+
* quando o config NÃO declara `social`.
|
|
42
47
|
*/
|
|
43
48
|
social?: AuthSocialConfig;
|
|
44
49
|
/**
|
|
45
50
|
* Rate-limiting (anti-brute-force) das rotas sensíveis. Necessário aqui (e não
|
|
46
51
|
* só no config) porque a aplicação do throttle acontece em tempo de registro de
|
|
47
|
-
* rota. Ligado por default (mesma resolução do config).
|
|
48
|
-
* config/
|
|
49
|
-
* (
|
|
52
|
+
* rota. Ligado por default (mesma resolução do config). Se `@adonisjs/limiter`
|
|
53
|
+
* não estiver configurado no host (config/limiter.ts), o throttle vira no-op
|
|
54
|
+
* (fail-safe).
|
|
55
|
+
*
|
|
56
|
+
* POLÍTICA: se o `defineConfig` declarou `rateLimit`, ele vence e este
|
|
57
|
+
* argumento é IGNORADO (com `console.warn` + entrada em `overriddenByConfig`).
|
|
58
|
+
* NÃO espelhe o config aqui — omitir a chave já herda dele.
|
|
50
59
|
*/
|
|
51
60
|
rateLimit?: RateLimitConfigInput;
|
|
52
61
|
/**
|
|
@@ -60,7 +69,12 @@ export interface AuthHostOptions {
|
|
|
60
69
|
*
|
|
61
70
|
* Necessário aqui (e não só no config) porque a decisão de montar as rotas é
|
|
62
71
|
* tomada em tempo de registro, antes do config (lazy) resolver.
|
|
63
|
-
*
|
|
72
|
+
*
|
|
73
|
+
* DOIS EIXOS: o LIGA/DESLIGA é POLÍTICA — se o `defineConfig` declarou
|
|
74
|
+
* `admin`, ele vence e o `true`/`false` daqui é IGNORADO (com `console.warn`
|
|
75
|
+
* + entrada em `overriddenByConfig`). O PREFIXO é ESTRUTURAL e o argumento
|
|
76
|
+
* sempre vence. Ou seja: com `admin` no config, passe no máximo
|
|
77
|
+
* `{ prefix: '...' }` aqui — nunca espelhe o `enabled`.
|
|
64
78
|
*
|
|
65
79
|
* @example
|
|
66
80
|
* // Prefixo padrão
|
|
@@ -82,7 +96,11 @@ export interface AuthHostOptions {
|
|
|
82
96
|
*
|
|
83
97
|
* Necessário aqui (e não só no config) porque a decisão de montar as rotas é
|
|
84
98
|
* tomada em tempo de registro, antes do config (lazy) resolver.
|
|
85
|
-
*
|
|
99
|
+
*
|
|
100
|
+
* DOIS EIXOS, como `admin`: o LIGA/DESLIGA é POLÍTICA (o `defineConfig`
|
|
101
|
+
* vence e o argumento é IGNORADO, com `console.warn`), o PREFIXO é
|
|
102
|
+
* ESTRUTURAL (o argumento vence). Com `adminApi` no config, passe no máximo
|
|
103
|
+
* `{ prefix: '...' }` aqui.
|
|
86
104
|
*
|
|
87
105
|
* @example
|
|
88
106
|
* // Prefixo padrão (back-compat)
|
|
@@ -98,7 +116,10 @@ export interface AuthHostOptions {
|
|
|
98
116
|
* Métodos de sudo cujas rotas devem ser montadas. Necessário aqui (e não só
|
|
99
117
|
* no config) porque a decisão de MONTAR rotas acontece em tempo de registro,
|
|
100
118
|
* antes de o config lazy resolver — mesma razão de `social`/`admin`/`rateLimit`.
|
|
101
|
-
*
|
|
119
|
+
*
|
|
120
|
+
* POLÍTICA: se o `defineConfig` declarou `sudo.methods`, ele vence e este
|
|
121
|
+
* argumento é IGNORADO (com `console.warn` + entrada em `overriddenByConfig`).
|
|
122
|
+
* NÃO espelhe o config aqui — omitir a chave já herda dele.
|
|
102
123
|
*
|
|
103
124
|
* SUBSTITUI os defaults, não acrescenta: a lista é do host. Quem quer manter
|
|
104
125
|
* senha/passkey ao lado do método novo os inclui explicitamente
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adonis-agora/authkit-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.57.1",
|
|
4
4
|
"description": "AdonisJS OIDC/OAuth2 provider (Identity Provider) toolkit: ejectable auth server with sessions, rate-limiting, MFA/TOTP, audit log, federated logout and OpenTelemetry metrics.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "dudousxd",
|
|
7
|
-
"homepage": "https://github.com/DavideCarvalho/adonis-authkit/tree/main/packages/authkit-server#readme",
|
|
7
|
+
"homepage": "https://github.com/DavideCarvalho/adonis-agora-authkit/tree/main/packages/authkit-server#readme",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
10
|
"url": "https://github.com/DavideCarvalho/adonis-agora-authkit.git",
|
|
11
11
|
"directory": "packages/authkit-server"
|
|
12
12
|
},
|
|
13
13
|
"bugs": {
|
|
14
|
-
"url": "https://github.com/DavideCarvalho/adonis-authkit/issues"
|
|
14
|
+
"url": "https://github.com/DavideCarvalho/adonis-agora-authkit/issues"
|
|
15
15
|
},
|
|
16
16
|
"keywords": [
|
|
17
17
|
"adonisjs",
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
"oidc-provider": "9.11.3",
|
|
109
109
|
"otplib": "12.0.1",
|
|
110
110
|
"qrcode": "1.5.4",
|
|
111
|
-
"@adonis-agora/authkit-core": "0.7.
|
|
111
|
+
"@adonis-agora/authkit-core": "0.7.1"
|
|
112
112
|
},
|
|
113
113
|
"devDependencies": {
|
|
114
114
|
"@adonis-agora/durable": "0.22.0",
|
|
@@ -150,7 +150,7 @@
|
|
|
150
150
|
"react-error-boundary": "6.1.2",
|
|
151
151
|
"nuqs": "2.9.5",
|
|
152
152
|
"recharts": "3.10.1",
|
|
153
|
-
"@adonis-agora/authkit-react": "0.18.
|
|
153
|
+
"@adonis-agora/authkit-react": "0.18.1"
|
|
154
154
|
},
|
|
155
155
|
"scripts": {
|
|
156
156
|
"build": "node scripts/build_host_css.mjs && node scripts/build_webauthn.mjs && node scripts/build_ui.mjs && node -e \"const fs=require('node:fs');for(const d of ['build/stubs','build/host/views'])fs.rmSync(d,{recursive:true,force:true})\" && tsc && node -e \"require('node:fs').cpSync('src/host/assets','build/src/host/assets',{recursive:true})\" && node -e \"require('node:fs').cpSync('stubs','build/stubs',{recursive:true,filter:(s)=>!s.endsWith('.ts')})\" && node -e \"const fs=require('node:fs');if(fs.existsSync('assets'))fs.cpSync('assets','build/assets',{recursive:true})\" && node -e \"require('node:fs').cpSync('src/host/views','build/host/views',{recursive:true})\" && node -e \"const fs=require('node:fs');fs.mkdirSync('build/host/ui',{recursive:true});fs.readdirSync('src/host/ui').filter(f=>f.endsWith('.html')).forEach(f=>fs.copyFileSync('src/host/ui/'+f,'build/host/ui/'+f))\" && node -e \"require('node:fs').copyFileSync('commands/commands.json','build/commands/commands.json')\" && node -e \"const fs=require('node:fs');fs.mkdirSync('build/src/password',{recursive:true});fs.copyFileSync('src/password/common_passwords.txt','build/src/password/common_passwords.txt')\"",
|