@adonis-agora/authkit-client 0.20.4 → 1.0.0-rc.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +957 -0
  2. package/README.md +47 -12
  3. package/build/auth.d.ts +2 -0
  4. package/build/auth.js +1 -0
  5. package/build/authkit_context_middleware.d.ts +1 -0
  6. package/build/authkit_context_middleware.js +2 -0
  7. package/build/commands/configure.d.ts +10 -0
  8. package/build/commands/configure.js +57 -2
  9. package/build/index.d.ts +3 -2
  10. package/build/index.js +1 -1
  11. package/build/providers/authkit_client_provider.d.ts +8 -1
  12. package/build/providers/authkit_client_provider.js +28 -12
  13. package/build/src/authenticator.d.ts +4 -3
  14. package/build/src/authenticator.js +6 -3
  15. package/build/src/host/authkit_client_guard.d.ts +51 -36
  16. package/build/src/host/authkit_client_guard.js +97 -46
  17. package/build/src/host/dashboard_guard.d.ts +3 -7
  18. package/build/src/host/dashboard_guard.js +3 -7
  19. package/build/src/host/request_authenticator.d.ts +28 -10
  20. package/build/src/host/request_authenticator.js +5 -3
  21. package/build/src/middleware/authkit_context_middleware.d.ts +3 -4
  22. package/build/src/middleware/authkit_context_middleware.js +5 -4
  23. package/build/src/middleware/backchannel_revocation_middleware.d.ts +1 -1
  24. package/build/src/middleware/backchannel_revocation_middleware.js +1 -1
  25. package/build/src/middleware/require_org_middleware.d.ts +3 -2
  26. package/build/src/middleware/require_org_middleware.js +5 -4
  27. package/build/src/resolvers/dpop_proof.d.ts +34 -0
  28. package/build/src/resolvers/dpop_proof.js +92 -0
  29. package/build/src/resolvers/factory.d.ts +5 -0
  30. package/build/src/resolvers/factory.js +1 -0
  31. package/build/src/resolvers/jwt_resolver.d.ts +9 -0
  32. package/build/src/resolvers/jwt_resolver.js +47 -3
  33. package/build/stubs/config/auth.stub +30 -0
  34. package/build/stubs/config/authkit_client.stub +2 -1
  35. package/build/stubs/middleware/auth_middleware.stub +25 -0
  36. package/build/stubs/middleware/silent_auth_middleware.stub +16 -0
  37. package/build/types.d.ts +5 -32
  38. package/build/types.js +1 -1
  39. package/package.json +12 -17
  40. package/skills/authkit-rp-client/SKILL.md +102 -47
  41. package/stubs/config/auth.stub +30 -0
  42. package/stubs/config/authkit_client.stub +2 -1
  43. package/stubs/middleware/auth_middleware.stub +25 -0
  44. package/stubs/middleware/silent_auth_middleware.stub +16 -0
  45. package/build/src/host/ctx_auth.d.ts +0 -6
  46. package/build/src/host/ctx_auth.js +0 -8
  47. package/build/src/middleware/auth_middleware.d.ts +0 -13
  48. package/build/src/middleware/auth_middleware.js +0 -13
  49. package/build/src/middleware/authkit_middleware.d.ts +0 -6
  50. package/build/src/middleware/authkit_middleware.js +0 -24
  51. package/build/src/middleware/silent_auth_middleware.d.ts +0 -13
  52. package/build/src/middleware/silent_auth_middleware.js +0 -15
package/CHANGELOG.md ADDED
@@ -0,0 +1,957 @@
1
+ # @adonis-agora/authkit-client
2
+
3
+ ## 1.0.0-rc.0
4
+
5
+ ### Major Changes
6
+
7
+ - [#436](https://github.com/DavideCarvalho/adonis-agora-authkit/pull/436) [`c942fe3`](https://github.com/DavideCarvalho/adonis-agora-authkit/commit/c942fe30483346217c9c89112e13db0d4a65c647) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - AuthKit 1.0. See the [Migrating to 1.0](https://github.com/DavideCarvalho/adonis-agora-authkit/blob/main/apps/docs/content/docs/migrating-to-1-0.mdx) guide.
8
+
9
+ Breaking changes (`@adonis-agora/authkit-server`):
10
+
11
+ - `withMfa` is removed. MFA state lives in the lib-owned `auth_mfa` table, so drop the mixin from your `AuthUser` model's `compose(...)`.
12
+ - `markSudo` is no longer exported. Grant sudo with `completeSudo(sudoContextFrom(ctx), methodId)`, which also writes the `sudo.confirmed` audit event, remembers the method and redirects to the validated `return_to`.
13
+ - The email-change confirmation link is sent through `mail.onEmailChangeConfirm` only. Without it, AuthKit sends its built-in email; `onEmailVerification` no longer receives email-change confirmations.
14
+ - The `clients` option of `defineConfig` is removed. Create clients in the admin console, through the Admin API or with `node ace authkit:clients:create` (new `--client-secret` flag keeps an existing secret). `buildImpersonationPanel(cfg, targetId, clients)` now requires `clients`, and the impersonation curl always shows the `<CLIENT_SECRET>` placeholder.
15
+ - `inertiaRenderer({ prefix, views })`: `views` is required. Screens not listed render with the built-in Edge view. `AuthkitScreen` is now the exact union of the screens AuthKit renders (adds `throttled`, `agents/consent`, `agents/done`; no arbitrary strings), and every screen's props are exported: `AuthkitScreenProps['<view>']` plus named types (`LoginProps`, `SessionExpiredProps`, …). The controllers are checked against them. Hosts declare screens of their own by augmenting `AuthkitScreenProps` (`declare module '@adonis-agora/authkit-server'`).
16
+ - The Admin API client body reads `grantTypes` only; the `grants` alias is gone (responses still return `grants`).
17
+ - `lucidAccountStore` always mounts password history over the model's connection (`auth_password_history`).
18
+ - `/account/orgs/json`, `/account/orgs/invitations/json` and `/account/orgs/:id/json` are removed; use `/account/api/orgs/*`.
19
+ - `GET /account/api/apps` entries gain `name` and `logoUrl`.
20
+
21
+ - The admin console reads its config from a `<script type="application/json" id="authkit-admin-config">` data block (CSP-safe) instead of an inline `window.__AUTHKIT__` script; the dev fallback is gone.
22
+ - The admin client DTO returns `grantTypes` (was `grants`), plus `clientName` and `logoUri`, which the console and the Admin API can now set (`null` removes them, as it does `backchannelLogoutUri`). `GET {admin}/api/clients/:id` exists.
23
+ - Anonymous JSON callers of the admin and account JSON APIs get `401` (and `403` without an admin role) instead of a redirect to the login page.
24
+ - Fixes: the Redis adapter's `list()` honours the connection `keyPrefix` (sessions, apps and admin lists were empty); a password login posted without a password is an invalid-credentials answer, not a 500.
25
+
26
+ Breaking changes (`@adonis-agora/authkit-core`):
27
+
28
+ - `ClientConfig` and `ResolvedAuthServerConfig.clients` are removed.
29
+
30
+ Breaking changes (`@adonis-agora/authkit-client`):
31
+
32
+ - `@adonisjs/auth` is a required peer. `ctx.auth` is `@adonisjs/auth`, backed by the AuthKit session through `authkitClientGuard`; `ctx.authkit` (from `authkit_context_middleware`) carries the AuthKit-only data (identity, `hasGlobalRole`, active org, `toSharedProps`).
33
+ - `authkit_middleware`, `auth_middleware` and `silent_auth_middleware` (and their subpaths) are removed: `ctx.auth` comes from `@adonisjs/auth`, and `middleware.auth()` / `silentAuth` are the `#middleware/auth_middleware` / `#middleware/silent_auth_middleware` files `node ace configure` publishes. `require_org_middleware` stays. `@adonis-agora/authkit-client/types` no longer declares `HttpContext.auth`; type `ctx.authkit.getUser()` through the `AuthkitUserType` interface.
34
+ - `node ace configure @adonis-agora/authkit-client` installs `@adonisjs/auth` when missing (`--no-install` prints the command), writes `config/auth.ts` with `authkitClientGuard` + `sessionUserProvider` (`--model`, default `#models/user`; an existing file is left alone and the guard to add is printed), registers `@adonisjs/auth/auth_provider`, `initialize_auth_middleware` + `authkit_context_middleware`, and publishes the named `auth` / `silentAuth` middleware.
35
+ - `authkitClientGuard` takes its user from `resolveUser` when one is configured (so `lucidMirror` provisions the row on first login, and what it loads is on `ctx.auth.user`, the same instance as `ctx.authkit.getUser()`), with the provider as the fallback.
36
+ - New `authkitIdentityProvider()`: a user provider with no database; `ctx.auth.user` is the AuthKit `Identity`.
37
+ - New `authkitClientGuard({ provider, resolver })` option: a per-guard resolver for API routes (bearer JWT, opaque, PAT).
38
+ - `resolvers.jwt({ tokenSource: 'bearer' })` accepts `Authorization: DPoP <jwt>` with a valid `DPoP` proof for `cnf.jkt`-bound tokens, and refuses DPoP-bound tokens sent as `Bearer`.
39
+ - `UnauthorizedAccessConstructor` is no longer exported, and `AuthkitClientGuard` no longer takes an exception class; it always throws `@adonisjs/auth`'s `E_UNAUTHORIZED_ACCESS`.
40
+
41
+ Breaking changes (`@adonis-agora/authkit-sdk`):
42
+
43
+ - `clients.*` return `grantTypes` (was `grants`), plus `clientName` and `logoUri`.
44
+
45
+ Breaking changes (`@adonis-agora/authkit-react`):
46
+
47
+ - `createAuthkitClient()` no longer reads `window.__AUTHKIT__`: pass `baseUrl` for `client.admin.*` and `csrfToken`.
48
+ - Admin response types match the server: `users.remove` / `clients.remove` → `{ ok, deleted }`, `users.resetPassword` → `{ ok, email }`, `users.disable` / `enable` → the user, `SettingListResult.locked`; `AdminClient.grants` → `grantTypes` (+ `clientName`, `logoUri`); `UpdateUserInput` is `{ globalRoles? }`, `CreateUserInput` takes no `null`.
49
+ - New: `client.account.agents.list()` / `revoke()`, `useAccountAgentsQueryOptions`, `useRevokeAccountAgentMutationOptions`.
50
+ - Peers: `react` / `react-dom` `^19.0.0`, `@inertiajs/react` `^2.0.0 || ^3.0.0`.
51
+
52
+ - `useProfile`, `useSessions`, `useAuthorizedApps`, `useOrganizations`, `useOrganization`, `useOrgInvitations`, `useSwitchOrganization` and their types are removed, with the `profile`, `sessions`, `apps`, `orgs` and `orgInvitations` keys of `endpoints`. Use the query options (`useMeQueryOptions`, `useAccountSessionsQueryOptions`, `useAppsQueryOptions`, `useAccountOrgsQueryOptions`, …).
53
+ - `UserProfile`, `AuthorizedApps`, `OrganizationSwitcher` and `OrganizationProfile` need `QueryClientProvider` and `AuthkitClientProvider`.
54
+
55
+ All packages:
56
+
57
+ - `@adonis-agora/*` peer ranges accept 1.x and its release candidates (`<2.0.0 || >=1.0.0-rc.0 <2.0.0`): `durable`, `media`, `telescope` (authkit-server), `resilience` (authkit-client), `authkit-server` (authkit-sdk).
58
+ - Node.js `>=24` is required (tested on 24 and 26).
59
+
60
+ ### Patch Changes
61
+
62
+ - Updated dependencies [[`c942fe3`](https://github.com/DavideCarvalho/adonis-agora-authkit/commit/c942fe30483346217c9c89112e13db0d4a65c647)]:
63
+ - @adonis-agora/authkit-core@1.0.0-rc.0
64
+
65
+ ## 0.20.5
66
+
67
+ ### Patch Changes
68
+
69
+ - fix(deps): update dependency jose to v6.2.15 ([#405](https://github.com/DavideCarvalho/adonis-agora-authkit/issues/405))
70
+
71
+ ## 0.20.4
72
+
73
+ ### Patch Changes
74
+
75
+ - fix(deps): update dependency jose to v6.2.14 ([#388](https://github.com/DavideCarvalho/adonis-agora-authkit/issues/388))
76
+
77
+ ## 0.20.3
78
+
79
+ ### Patch Changes
80
+
81
+ - [#361](https://github.com/DavideCarvalho/adonis-agora-authkit/pull/361) [`1b9c90c`](https://github.com/DavideCarvalho/adonis-agora-authkit/commit/1b9c90ced4356d2c754e850e307954455ddeeb3a) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Performance: `lucidRevocationStore` imports the Lucid `db` service module once per process instead of running a dynamic `import()` on every `isRevoked` call (every authenticated request when back-channel logout is on). It still reads the service's live binding on each call, and a failed import is retried.
82
+ - Updated dependencies [[`1b9c90c`](https://github.com/DavideCarvalho/adonis-agora-authkit/commit/1b9c90ced4356d2c754e850e307954455ddeeb3a)]:
83
+ - @adonis-agora/authkit-core@0.10.1
84
+
85
+ ## 0.20.2
86
+
87
+ ### Patch Changes
88
+
89
+ - [#349](https://github.com/DavideCarvalho/adonis-agora-authkit/pull/349) [`5512d90`](https://github.com/DavideCarvalho/adonis-agora-authkit/commit/5512d907f1a1960f7387651616c2a12d25abfa14) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - `discoverEndpoints` shares one in-flight fetch per issuer, keeps serving an expired document while a single background refetch replaces it, and aborts the request after 10 s. The `OpaqueResolver` cache (with `cacheTtlMs`) now expires an entry at the token's `exp` when that comes first, and is capped at 10,000 tokens. `lucidMirror` returns an up-to-date row from a plain `findBy` instead of a locking `updateOrCreate` transaction on every request.
90
+
91
+ ## 0.20.1
92
+
93
+ ### Patch Changes
94
+
95
+ - fix(deps): update dependency jose to v6.2.13 ([#323](https://github.com/DavideCarvalho/adonis-agora-authkit/issues/323))
96
+
97
+ ## 0.20.0
98
+
99
+ ### Minor Changes
100
+
101
+ - [#269](https://github.com/DavideCarvalho/adonis-agora-authkit/pull/269) [`b0ca480`](https://github.com/DavideCarvalho/adonis-agora-authkit/commit/b0ca4802419aba93a9f913775f697cc4075cff88) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Drop Node 20, which reached end-of-life on 2026-04-30, and Node 22, which AdonisJS 7 does not support (it requires Node >=24): `engines.node` is now `>=24`. The supported Node lines are 24 and 26, and CI runs the test suite on each of them.
102
+
103
+ ### Patch Changes
104
+
105
+ - Updated dependencies [[`b0ca480`](https://github.com/DavideCarvalho/adonis-agora-authkit/commit/b0ca4802419aba93a9f913775f697cc4075cff88)]:
106
+ - @adonis-agora/authkit-core@0.10.0
107
+
108
+ ## 0.19.2
109
+
110
+ ### Patch Changes
111
+
112
+ - [#265](https://github.com/DavideCarvalho/adonis-agora-authkit/pull/265) [`e94c12f`](https://github.com/DavideCarvalho/adonis-agora-authkit/commit/e94c12f708562392af9a0b0d593f554702d382c0) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - `AuthkitClientManager.completeAuthorization` checks that a callback belongs to the pending authorization (`missing_pending`, `state_mismatch`) before it discovers the IdP. A stale or forged callback that arrived while discovery was failing surfaced as an `OidcDiscoveryError` (a 500 in `registerOidcClient`) instead of a restartable `OidcCallbackError` that sends the user back to login.
113
+
114
+ - [#266](https://github.com/DavideCarvalho/adonis-agora-authkit/pull/266) [`660ce2d`](https://github.com/DavideCarvalho/adonis-agora-authkit/commit/660ce2d13a94fb971d2e14a2bfa94eeb04b90a36) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - `bindValue('authkit.client', fake)` replaces the manager again. Since 0.19 the manager is bound by class and the string key was an `alias`, and the container follows an alias before it checks bound values: a fake bound under the string key was silently ignored, and the real manager came back. This is how apps replaced it in tests before 0.19, and the changelog promised the key was kept. The key is now a binding that resolves the class: the same singleton, overridable under either name, and a `swap` of the class reaches it even after its first use.
115
+
116
+ ## 0.19.1
117
+
118
+ ### Patch Changes
119
+
120
+ - [#260](https://github.com/DavideCarvalho/adonis-agora-authkit/pull/260) [`f374913`](https://github.com/DavideCarvalho/adonis-agora-authkit/commit/f37491386d6b7a5ce6874b8b3cd5740eceb05872) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - `node ace configure @adonis-agora/authkit-client` works again: a backtick in a comment of the `oidc_session_controller` stub broke the stub template engine. The stub compile test never failed because `assert.doesNotThrow(fn, message)` treats the string as an error-message matcher; it now collects compile errors explicitly, and a new test runs the real `configure` hook against a scratch app. `configure` also points to `registerOidcClient(router)` as the way to register the session routes, and the getting-started guide and the agent skill teach it first, keeping the ejected controller for apps that customise the flow ([#202](https://github.com/DavideCarvalho/adonis-agora-authkit/issues/202)).
121
+
122
+ ## 0.19.0
123
+
124
+ ### Minor Changes
125
+
126
+ - [#256](https://github.com/DavideCarvalho/adonis-agora-authkit/pull/256) [`95ba5fa`](https://github.com/DavideCarvalho/adonis-agora-authkit/commit/95ba5fa80c5269940f8a9e227d792bcd896c3ce2) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Third-party IdPs (Keycloak, Auth0, Okta, Entra) now work with the integrated client, and the id_token is validated ([#237](https://github.com/DavideCarvalho/adonis-agora-authkit/issues/237)).
127
+
128
+ - **Discovery by default.** `defineConfig` gains `discovery` (default `true`) and `endpoints` (per-field overrides). The endpoints published at `{issuer}/.well-known/openid-configuration` are used everywhere: `registerOidcClient` login/callback/logout, `maybeRefresh`, impersonation, back-channel logout and the default `jwksUri` / introspection URL of `resolvers.jwt()` / `resolvers.opaque()`. Discovery is lazy (the app boots while the IdP is down), a failure throws `OidcDiscoveryError` and is retried on the next request, and a document discovered earlier keeps being served while refetches fail. The document's `issuer` must match the configured one; its exact value is used for `iss` checks, which fixes trailing-slash issuers (Auth0). `discovery: false` restores the previous behaviour (authkit-server route layout + `endpoints`), e.g. for tests that run against a fake issuer.
129
+ - **id_token validation.** New `validateIdToken` (signature, `iss`, `aud`, `azp`, `exp`, `iat`, `nonce`, `max_age`, `sub`). The callback now sends and checks a `nonce` and validates the id_token; a refreshed id_token must be valid and about the same user, otherwise the refresh is discarded.
130
+ - **New flow helpers.** `createAuthorizationRequest` / `completeAuthorization` (also as `AuthkitClientManager` methods, together with `endpoints()` and `validateIdToken()`) wrap state, nonce, PKCE, the RFC 9207 `iss` check and id_token validation; failures throw `OidcCallbackError` with a `code` and `restartable`.
131
+ - **Container binding by class.** `AuthkitClientManager` is bound by class (with `authkit.client` kept as an alias), so it can be used with `@inject()`. The scaffolded `OidcSessionController` uses it.
132
+ - **No more silent failures.** A failing refresh is logged as a warning; `/auth/logout` goes straight to the post-logout destination when the IdP publishes no `end_session_endpoint`.
133
+ - Token endpoint failures now carry the IdP's `error` / `error_description` (`Token endpoint returned 400: not_allowed (…)`) instead of a bare status.
134
+ - `discoverEndpoints` gains `onError: 'fallback' | 'throw'`. With the default `'fallback'`, the convention fallback is no longer cached, and a document without a matching `issuer` is treated as unusable.
135
+ - `OidcEndpoints.issuer` is now always present: the document's exact issuer when discovered, the configured one otherwise (`conventionEndpoints(issuer)` fills it in). Code that builds an `OidcEndpoints` literal by hand must add it.
136
+ - The context passed to `ResolverFactory.resolver()` now always carries `endpoints` (the resolved IdP endpoints, called per request) and `logger`; the built-in resolvers read the endpoints on every request, so a rotated `jwks_uri` takes effect without a restart. Code that calls `factory.resolver({ ... })` by hand, typically in tests, must pass both — e.g. `endpoints: async () => conventionEndpoints(issuer), logger: { warn: () => {} }`.
137
+ - Back-channel logout reuses the cached remote JWKS instead of fetching the IdP keys on every `logout_token`.
138
+
139
+ ### Patch Changes
140
+
141
+ - [#255](https://github.com/DavideCarvalho/adonis-agora-authkit/pull/255) [`481051c`](https://github.com/DavideCarvalho/adonis-agora-authkit/commit/481051c86c67b2bf5026f7a49028d260236667c9) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Publish peer dependencies as ranges again (`^7.5.0` instead of `7.5.0`, etc.). A Renovate pinning pass had turned the peer catalogs into exact versions, so any upstream patch release (e.g. `@adonisjs/core` 7.5.1) fell outside the accepted peer range.
142
+
143
+ ## 0.18.9
144
+
145
+ ### Patch Changes
146
+
147
+ - [#253](https://github.com/DavideCarvalho/adonis-agora-authkit/pull/253) [`d6fc1b8`](https://github.com/DavideCarvalho/adonis-agora-authkit/commit/d6fc1b8c34037022f22c0a21e0a0866e7d716fa3) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - `maybeRefresh`: concurrent requests of the same session no longer get a 401 when the access token
148
+ expires. The refresh is still deduplicated per session id, but requests that wait for the in-flight
149
+ refresh now also write the renewed TokenSet (new access token and rotated refresh token) into their
150
+ own session — before, only the request that started the refresh got it, and the others kept the
151
+ expired access token and the already-rotated refresh token. The in-flight entry is now always
152
+ cleared, even when the refresh fails.
153
+
154
+ ## 0.18.8
155
+
156
+ ### Patch Changes
157
+
158
+ - Updated dependencies [[`94644e6`](https://github.com/DavideCarvalho/adonis-agora-authkit/commit/94644e6b1d8d10e0fd3c4b57706cce46b70412cb)]:
159
+ - @adonis-agora/authkit-core@0.9.0
160
+
161
+ ## 0.18.7
162
+
163
+ ### Patch Changes
164
+
165
+ - [#215](https://github.com/DavideCarvalho/adonis-agora-authkit/pull/215) [`db4f3db`](https://github.com/DavideCarvalho/adonis-agora-authkit/commit/db4f3db082b47cd628d22826bfa5d9db91dd57c6) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - fix(authkit-client): opt-out do encaminhamento de query precisa ser `withQs(false)`
166
+
167
+ A correção anterior (0.18.6) passou `false` como segundo argumento de
168
+ `ctx.response.redirect(destino, false)`. **Isso não desliga o encaminhamento**
169
+ quando o app declara `redirect.forwardQueryString: true` no `config/app.ts`, que
170
+ é o caso comum: nessa situação o positional é ignorado e o `Redirect` herda a
171
+ configuração global, continuando a encaminhar. O sintoma seguia igual — o
172
+ callback mandava `code`/`state`/`iss` para o destino e o app terminava em
173
+ `/?code=…` depois do login.
174
+
175
+ O opt-out por redirect é o builder: `ctx.response.redirect().withQs(false).toPath(destino)`.
176
+ Os cinco redirects do `registerOidcClient` (login, `/auth/login` de recuperação,
177
+ destino pós-login, hook `afterLogin` e `end-session` do logout) passam a usá-lo.
178
+
179
+ O teste passava antes porque o `response` falso honrava o argumento posicional —
180
+ ou seja, testava uma premissa que o framework não cumpre. Ele agora modela o
181
+ comportamento real (config ligada ⇒ positional ignorado; só `withQs(false)`
182
+ desliga), então falha com a forma antiga e passa com a correta.
183
+
184
+ ## 0.18.6
185
+
186
+ ### Patch Changes
187
+
188
+ - [#213](https://github.com/DavideCarvalho/adonis-agora-authkit/pull/213) [`7e6b8ef`](https://github.com/DavideCarvalho/adonis-agora-authkit/commit/7e6b8ef81df0c2bb498d6b4728baa0f9abc4d0bb) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - fix(authkit-client): redirect de login/callback encaminhava a query string da request
189
+
190
+ O AdonisJS encaminha a query string da request atual no `redirect` por padrão
191
+ (`redirect.forwardQueryString`). O `registerOidcClient` chamava
192
+ `ctx.response.redirect(destino)` sem o segundo argumento, e **todos** os seus
193
+ destinos são URLs que a própria lib monta — então a query da request não tinha
194
+ por que ir junto. Duas consequências visíveis:
195
+
196
+ - **Pós-login:** o callback redireciona para o destino do app, mas arrastava
197
+ `code`/`state`/`iss` consigo. Quem entrava caía em `/?code=…&state=…&iss=…`
198
+ em vez de `/` — parecia que o botão "Entrar" não fazia nada.
199
+ - **Callback falho:** o redirect para `/auth/login` levava o `code`/`state`
200
+ antigos, que então eram encaminhados de novo para o authorize seguinte —
201
+ lixo de uma tentativa anterior viajando pelo fluxo.
202
+
203
+ Os cinco redirects (`login`, `/auth/login` de recuperação, destino pós-login,
204
+ hook `afterLogin` e `end-session` do logout) agora passam `forwardQueryString:
205
+ false`. O destino já carrega a query que precisa; nada da request atual deve ser
206
+ somado a ela.
207
+
208
+ ## 0.18.5
209
+
210
+ ### Patch Changes
211
+
212
+ - [#207](https://github.com/DavideCarvalho/adonis-agora-authkit/pull/207) [`9682830`](https://github.com/DavideCarvalho/adonis-agora-authkit/commit/96828307192ad4de7478c84b1e0cae3eefe18d0b) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - O controller ejetado (`stubs/controllers/oidc_session_controller.stub`) escrevia a sessão crua: `ctx.session.put(cfg.sessionKey, tokenSet)` no callback e `ctx.session.forget(sessionKey)` no logout. Isso não limpa o `impersonationBinding` nem a credencial de impersonação parqueada — o refresh token do ator continuava serializado no cookie da próxima identidade, e o logout deixava a credencial viva. O stub agora usa o manager: `manager.startSession(ctx, tokenSet)` no callback e `manager.endSession(ctx)` no logout, mantendo PKCE/state e a troca de code. O README passa a recomendar `registerOidcClient(router)` e documenta o controller apenas como caminho de customização, deixando explícito o requisito de `startSession`/`endSession`. Teste de regressão assere que o stub chama o manager e não contém a escrita crua.
213
+
214
+ ## 0.18.4
215
+
216
+ ### Patch Changes
217
+
218
+ - bc32ea4: Bump runtime dependencies to their latest releases.
219
+
220
+ - `@simplewebauthn/server` and `@simplewebauthn/browser` go to `14.x`. The committed
221
+ `src/host/assets/webauthn.js` bundle was regenerated from the new `@simplewebauthn/browser`
222
+ (the `check:webauthn-bundle` guard would have caught the drift otherwise). The `authkit-react`
223
+ peer was **widened** to `^13.3.0 || ^14.0.0` instead of moved, so apps still on 13 keep
224
+ installing cleanly.
225
+ - `oidc-provider` 9.12.0 → 9.12.2 and `jose` 6.2.10 → 6.2.12 (patch releases on the token/JWT path).
226
+
227
+ No API change on our side: typecheck, tests, packaging smoke and the WebAuthn bundle check all pass.
228
+
229
+ ## 0.18.3
230
+
231
+ ### Patch Changes
232
+
233
+ - dcb3408: `node ace configure @adonis-agora/authkit-client` sempre crashava com `SyntaxError: Unexpected identifier 'resolveRoles'`. O stub publicado (`config/authkit_client.stub`) tinha um comentário com o nome `resolveRoles` entre crases (markdown-style), e o codemod de stubs (`tempura`) compila o conteúdo bruto do stub envolvendo-o numa template literal JS — a crase não-escapada fechava essa literal cedo. Removidas as crases do comentário (não havia motivo funcional para elas ali). Adicionado um teste que compila TODO `.stub` publicado do pacote via `tempura`, para pegar essa classe de regressão automaticamente em vez de só checar a existência do arquivo.
234
+
235
+ ## 0.18.2
236
+
237
+ ### Patch Changes
238
+
239
+ - 76b1314: fix(maybeRefresh): deduplicate concurrent refresh token requests per session
240
+
241
+ When multiple requests arrive simultaneously and the access token is within
242
+ the REFRESH_SKEW_MS window, every request would independently fire a
243
+ refresh token grant to the IdP. Since refresh tokens rotate, only the first
244
+ succeeds — the remaining N-1 requests fail with an already-invalidated
245
+ refresh token, creating unnecessary load and log noise.
246
+
247
+ This commit introduces an in-memory dedup map keyed by `sessionId`:
248
+ concurrent requests to the same session share a single in-flight refresh
249
+ promise. Sessions without a `sessionId` (e.g. some test contexts) fall
250
+ back to the original behavior.
251
+
252
+ ## 0.18.1
253
+
254
+ ### Patch Changes
255
+
256
+ - a6d271c: Ship TanStack Intent AI-agent skills with each package (`skills/` added to `files`), add the `tanstack-intent` keyword, and take a devDependency on `@tanstack/intent` for skill validation.
257
+
258
+ ## 0.18.0
259
+
260
+ ### Minor Changes
261
+
262
+ - 813a321: Multi-tenancy: `orgId` de primeira classe no evento, `orgId`/`orgSlug`/`orgRole` na `Identity`, e o middleware `requireOrg`
263
+
264
+ Três buracos no caminho de multi-tenancy por organização, achados ao seguir o
265
+ fluxo inteiro (org criada → claim → contexto → RBAC escopado):
266
+
267
+ **1. O barramento de diagnostics não dizia QUAL org.** `redactAuditEventForDiagnostics`
268
+ dropa `metadata` inteiro por LGPD (é campo livre e carrega PII — o e-mail do
269
+ convidado, por exemplo). Só que o `orgId` dos eventos de organização vivia
270
+ justamente ali. Resultado: um assinante de `agora:authkit:organization.created`
271
+ — o provisioning do `@adonis-agora/authz`, entre outros — recebia o tipo do
272
+ evento e nada mais, o que torna o hook inútil na prática. Além disso o
273
+ `organization.created` self-service auditava só `{ slug }`, sem id nenhum.
274
+
275
+ `orgId` agora é campo de primeira classe do `AuditEvent`, preenchido nos 15
276
+ call-sites de eventos de organização (`organization.deactivated` não tem org, é
277
+ a limpeza), preservado na projeção de diagnostics junto dos demais ids opacos
278
+ (`accountId`/`actorId`/`clientId`) e incluído no corpo do webhook. A redação de
279
+ PII continua intacta: `email`, `ip` e `metadata` seguem fora do barramento.
280
+
281
+ **2. A `Identity` não expunha a org.** O tenant ativo só existia em
282
+ `identity.raw.org_id`, sem tipo, e cada app reescrevia a derivação. Agora
283
+ `identity.orgId`, `identity.orgSlug` e `identity.orgRole` são campos da
284
+ `Identity`, preenchidos por `buildIdentityFromClaims` (portanto nos três
285
+ resolvers: jwt, pat e opaque). A tabela de claims aceitas — que já existia
286
+ duplicada dentro da ponte de contexto — virou `ORG_ID_CLAIMS` +
287
+ `deriveOrgId`/`deriveOrgSlug`/`deriveOrgRole` no `authkit-core`, e a ponte
288
+ passou a consumi-la. Os aliases de IdPs de terceiros (`tid`,
289
+ `organization_id`, `tenant_id`, `active_organization_id`) continuam valendo,
290
+ agora num lugar só.
291
+
292
+ **3. Não havia como exigir org ativa.** `RequireOrgMiddleware`
293
+ (`@adonis-agora/authkit-client/require_org_middleware`) barra request
294
+ autenticada mas sem tenant. Isso importa porque "logado" e "dentro de um
295
+ tenant" são coisas distintas: sem a barreira, a request chega no controller com
296
+ tenant indefinido e a checagem escopada do authz cai no escopo GLOBAL — o pior
297
+ lugar para se cair por acidente. Fail-closed, com `mode: 'api'` (403
298
+ `no_active_organization` em vez de redirect) e `oneOf` para restringir a um
299
+ conjunto conhecido de orgs.
300
+
301
+ ### Patch Changes
302
+
303
+ - Updated dependencies [813a321]
304
+ - @adonis-agora/authkit-core@0.8.0
305
+
306
+ ## 0.17.4
307
+
308
+ ### Patch Changes
309
+
310
+ - b97f28e: Importing the middleware no longer forces `HttpContext.auth` on your app.
311
+
312
+ **If you pinned to 0.17.1 to get your typecheck passing, this releases you.**
313
+
314
+ 0.17.2 added `import '../../types.js'` to the middleware's emitted declarations so
315
+ that `ctx.auth` would be typed for apps that had no declaration of their own. But
316
+ that same file also carries the library's _unparameterised_
317
+ `auth: Authenticator`, and `start/kernel.ts` imports the middleware — so the
318
+ declaration entered every consumer's type program.
319
+
320
+ `HttpContext.auth` declared twice with different types does not merge.
321
+ TypeScript keeps whichever declaration it reached first and reports the conflict
322
+ on the other; that conflict lands inside a `.d.ts`, where `skipLibCheck` — on in
323
+ every AdonisJS app — discards it. The library's file is reached first through the
324
+ kernel, so an app's own `auth: Authenticator<AppUser>` lost and `getUser()`
325
+ collapsed to `unknown` **across the entire codebase**. One app went from 24 type
326
+ errors to 351, another from 0 to 105, with nothing pointing at the cause.
327
+
328
+ The two augmentations are now separate modules:
329
+
330
+ - `container_bindings.ts` declares only `ContainerBindings['authkit.client']`, a
331
+ key nothing else can claim. The provider and the middleware import this, so
332
+ `containerResolver.make('authkit.client')` stays typed.
333
+ - `types.ts` declares only `HttpContext.auth`, and **nothing in the package
334
+ imports it**. Apps that want the library's default typing opt in with
335
+ `import '@adonis-agora/authkit-client/types'`; apps that declare their own
336
+ parameterised version are left alone.
337
+
338
+ The library's middleware reads and writes `ctx.auth` through a local cast rather
339
+ than a global declaration, so the knowledge stays inside the package.
340
+
341
+ Nothing changes at runtime, and no app-level change is required: if you already
342
+ declare `auth: Authenticator<AppUser>`, it now simply wins, because it is the
343
+ only declaration in the program.
344
+
345
+ A spec walks the emitted declaration graph and fails if any consumer entrypoint
346
+ reaches the `HttpContext.auth` augmentation again — the monorepo's own typecheck
347
+ compiles every file in one program and structurally cannot catch this.
348
+
349
+ `@adonis-agora/authkit-server` was checked for the same defect and does not have
350
+ it: it ships no `HttpContext.auth`, and its four container bindings still reach
351
+ hosts through both the provider and the `./types` subpath. It gets the same guard
352
+ anyway, because the thing protecting it is easy to break by accident —
353
+ `src/host/augmentations.ts` loads the framework's own augmentations with
354
+ `import type {} from '…'`, a form tsc erases from the emitted declarations, and
355
+ rewriting any one of them as a bare `import '…'` would inherit
356
+ `@adonisjs/auth`'s `HttpContext.auth` and reproduce this bug package-wide. Both
357
+ guards now also reject a bare side-effect import of any external module from a
358
+ shipped declaration file.
359
+
360
+ ## 0.17.3
361
+
362
+ ### Patch Changes
363
+
364
+ - f287ade: Widen the `@adonis-agora/*` peer ranges so they survive the peer's next minor.
365
+
366
+ Below 1.0.0 a caret does not mean "this minor and up" — it stops at the next
367
+ minor, so `^0.22.0` expands to `>=0.22.0 <0.23.0`. Every sibling package in this
368
+ ecosystem ships minors constantly, which meant **all four** `@adonis-agora/*`
369
+ peers were unsatisfiable against the current release of the package they name.
370
+ Under npm this is not a warning: installing `@adonis-agora/authkit-server`
371
+ alongside `@adonis-agora/durable@0.24.0` failed outright with
372
+ `ERESOLVE — Conflicting peer dependency: @adonis-agora/durable@0.22.0`.
373
+
374
+ Each floor was chosen from what the code actually calls, not from what the range
375
+ happened to say:
376
+
377
+ | peer | was | now | why that floor |
378
+ | -------------------------- | --------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------ |
379
+ | `@adonis-agora/durable` | `^0.22.0` | `>=0.7.0 <1.0.0` | first release with `ctx.localStep`, absent in 0.6.1 |
380
+ | `@adonis-agora/media` | `^0.1.0` | `>=0.5.0 <1.0.0` | first release exporting the `./single-file` subpath the avatar uploader imports, absent in 0.4.0 |
381
+ | `@adonis-agora/telescope` | `^0.1.0` | `>=0.1.0 <1.0.0` | all five imported types are shape-identical from 0.1.0 through 0.8.1 |
382
+ | `@adonis-agora/resilience` | `^0.1.0` | `>=0.1.0 <1.0.0` | `wrap()` has existed since 0.1.0, and the policy is duck-typed against a locally declared interface rather than imported |
383
+
384
+ The `^0.22.0` on durable in particular came from the `ctx.step` → `ctx.localStep`
385
+ migration and recorded the version current on that day, some fifteen minors above
386
+ what the migration actually required.
387
+
388
+ `@adonis-agora/authkit-sdk`'s peer on `@adonis-agora/authkit-server` gains the
389
+ same upper bound (`>=0.10.0 <1.0.0`), which it was missing entirely — it would
390
+ have accepted a future 1.0 with breaking changes.
391
+
392
+ A spec now scans every package manifest and fails on a caret or tilde over a 0.x
393
+ `@adonis-agora/*` peer, so this cannot come back quietly.
394
+
395
+ ## 0.17.2
396
+
397
+ ### Patch Changes
398
+
399
+ - 8f23a85: Ship the module augmentations so they actually reach a consuming app.
400
+
401
+ **The client.** `HttpContext.auth` was declared in the package's root `types.ts`,
402
+ and nothing reachable from `build/index.d.ts` referenced that file — so TypeScript
403
+ never loaded it in a host app and `ctx.auth` came back as `Property 'auth' does
404
+ not exist on type 'HttpContext'`, no matter what the app imported. Verified
405
+ against packed tarballs in a scratch AdonisJS app across five wiring variants; a
406
+ `/// <reference path>` straight at the built `types.d.ts` type-checked cleanly,
407
+ which isolates it to reachability rather than to the declarations. The
408
+ augmentation is now pulled in by a bare side-effect import from
409
+ `authkit_middleware` — the middleware that actually assigns `ctx.auth`, and the
410
+ one `configure` registers.
411
+
412
+ Putting that import in `index.ts` was considered and rejected: apps that hand
413
+ `ctx.auth` to `@adonisjs/auth` through `authkitClientGuard` would then load two
414
+ competing `HttpContext.auth` declarations, and because `skipLibCheck` is on in
415
+ every AdonisJS app the conflict is not reported — one simply wins by include
416
+ order. Anchoring on the middleware keeps the two owners of `ctx.auth` mutually
417
+ exclusive, the same way `@adonisjs/auth` does with its own
418
+ `initialize_auth_middleware`.
419
+
420
+ **The server** was a smaller problem than it first looked. Hosts _were_ getting
421
+ `app.container.make('authkit.server')` typed all along, because the service
422
+ provider carried its own copy of the `ContainerBindings` declaration and every
423
+ host registers the provider. What was broken is that `exports["./types"]` pointed
424
+ at the barrel rather than at the built `types.js`, so importing
425
+ `@adonis-agora/authkit-server/types` gave `Property 'authkit.server' does not
426
+ exist on type 'ContainerBindings'`.
427
+
428
+ Retargeting that subpath exposed a second problem: the root `types.ts` declared
429
+ one binding while the provider declared four, so the newly-live subpath was a
430
+ partial view. Two binding tables with nothing checking they agree is how they
431
+ drifted in the first place, so there is one table now — in `types.ts`, with the
432
+ provider reaching it through a side-effect import.
433
+
434
+ **`adonisjs.types` covers neither package.** No version of `@adonisjs/core`,
435
+ `@adonisjs/assembler` or `@adonisjs/application` in this repo's dependency tree
436
+ reads that package.json field. It is an AdonisJS 5 leftover, left alone.
437
+
438
+ ## 0.17.1
439
+
440
+ ### Patch Changes
441
+
442
+ - 1f15367: Point `homepage` and `bugs.url` at the repository's current name.
443
+
444
+ The repository was renamed to `adonis-agora-authkit`; `repository.url` followed,
445
+ `homepage` and `bugs.url` did not. Every package therefore shipped a manifest
446
+ that disagreed with itself, and the "Repository"/"Homepage" links on npm leaned
447
+ on GitHub's rename redirect — which lasts only until someone claims the old
448
+ name. All three fields now name the same repository.
449
+
450
+ - Updated dependencies [1f15367]
451
+ - @adonis-agora/authkit-core@0.7.1
452
+
453
+ ## 0.17.0
454
+
455
+ ### Minor Changes
456
+
457
+ - 659862c: Exporta `isAuthkitAdmin`/`authkitDashboardAuthorize`/`authkitDashboardMiddleware` — o gate admin dos dashboards embutidos, pronto pra plugar
458
+
459
+ Todo host que embute o console admin de uma lib irmã (`@adonis-agora/durable`,
460
+ `@adonis-agora/media`, `@adonis-agora/agent`, `@adonis-agora/telescope`) reescrevia
461
+ o mesmo gate: checar `ctx.auth.hasGlobalRole('ADMIN')` e traduzir pra QUALQUER
462
+ formato que o `config/*_dashboard.ts` daquela lib espera — `authorize: (ctx) =>
463
+ boolean` (durable/agent/telescope) ou `middleware: (ctx, next) => Promise<void>`
464
+ (media). Mesma checagem, dois shims hand-rolled por app.
465
+
466
+ `packages/authkit-client/src/host/dashboard_guard.ts` (novo subpath
467
+ `@adonis-agora/authkit-client/dashboard_guard`, também no entrypoint raiz) fixa a
468
+ checagem uma vez sobre o próprio `Authenticator` do authkit e expõe os dois
469
+ adapters prontos:
470
+
471
+ ```ts
472
+ // config/durable_dashboard.ts (authorize)
473
+ import { authkitDashboardAuthorize } from "@adonis-agora/authkit-client";
474
+ export default defineConfig({ authorize: authkitDashboardAuthorize() });
475
+
476
+ // config/media_dashboard.ts (middleware)
477
+ import { authkitDashboardMiddleware } from "@adonis-agora/authkit-client";
478
+ export default defineConfig({ middleware: authkitDashboardMiddleware() });
479
+ ```
480
+
481
+ `isAuthkitAdmin(ctx, { role? })` é o predicado por trás dos dois: resolve a
482
+ sessão via `getAuthkit(ctx)` (funciona tanto com o `ctx.auth` do
483
+ `authkit_middleware` legado quanto com o `authkitClientGuard` mais novo, sem
484
+ depender da augmentation de `HttpContext.auth` que cada host declara pro seu
485
+ próprio model de usuário — este módulo é da lib, não vê essa augmentation) e
486
+ checa `hasGlobalRole('ADMIN')` por padrão; `role` troca o nome da global role
487
+ pra quem usa outra convenção. Sem sessão -> `false`/`401`; sessão sem a role ->
488
+ `false`/`403` — mesma semântica que o `authorize`/`middleware` de cada lib já
489
+ espera de um retorno negativo.
490
+
491
+ Só cobre o caso que já usa o mecanismo NATIVO do authkit (`hasGlobalRole`) — apps
492
+ que gateiam admin por outra via (uma role de app separada, uma coluna
493
+ `isAdmin`, um pacote de authz por cima) continuam com o helper deles; nada aqui
494
+ migra esse mecanismo.
495
+
496
+ ## 0.16.0
497
+
498
+ ### Minor Changes
499
+
500
+ - 40bb1a8: Amarra o restore da impersonação à sessão que guardou a credencial, e faz a revogação central levá-la junto
501
+
502
+ **Segurança — leia antes de subir. Impersonações EM VOO caem no upgrade** (ver
503
+ "O que acontece no upgrade", no fim).
504
+
505
+ Dois defeitos, ambos no `AuthkitClientManager`.
506
+
507
+ **A — `stopImpersonating()` restaurava uma credencial que não sabia atribuir.**
508
+ `impersonate()` parqueia o TokenSet INTEIRO do ator — refresh token incluso —
509
+ em `${sessionKey}_impersonator`, e a única conferência do restore era se a chave
510
+ existia. Como nada na lib limpava essa chave, a credencial sobrevivia à sessão
511
+ que a guardou. A cadeia completa: um admin impersona alguém, faz logout, uma
512
+ outra identidade loga no MESMO cookie jar e chama o endpoint de stop — e recebe
513
+ o TokenSet do admin, mantido vivo indefinidamente pelo `maybeRefresh` a cada
514
+ request. Em versões anteriores, **a lib entregava a credencial de impersonação a
515
+ quem ficasse com a sessão depois.**
516
+
517
+ **B — a revogação central deixava a credencial parqueada.**
518
+ `BackchannelRevocationMiddleware` fazia `session.forget(sessionKey)` e só. É o
519
+ mecanismo que o operador usa para matar uma sessão de fora, e ele deixava o
520
+ refresh token do ator parqueado no browser. **Nenhum consumidor conseguia
521
+ corrigir isso de fora** — o middleware é da lib. O logout RP-initiated do
522
+ `registerOidcClient` tinha o mesmo furo.
523
+
524
+ **O que mudou.** `impersonate()` gera um nonce e escreve o mesmo valor nos dois
525
+ lados: no registro parqueado e dentro do token set ATIVO da sessão
526
+ (`TokenSet.impersonationBinding`). O slot ativo é o único que todo caminho de
527
+ fim-de-sessão já limpa, então uma troca de identidade apaga o vínculo por
528
+ construção — não por convenção. `stopImpersonating()` exige que os dois batam;
529
+ `maybeRefresh` propaga o nonce (renovar o token do alvo não muda a sessão, então
530
+ não pode trancar o ator). Recusa é **fail-closed**: a credencial órfã é
531
+ descartada, nunca devolvida, e o token set da sessão cai junto — uma recusa não
532
+ é uma tentativa a repetir, e ninguém fica preso impersonando. Revogação
533
+ back-channel e logout passaram a usar `manager.endSession(ctx)`, o único ponto
534
+ que conhece as duas chaves.
535
+
536
+ E o callback de login passou a usar `manager.startSession(ctx, tokenSet)`, o par
537
+ de `endSession()`. Recusar o restore já fecha o roubo, mas recusar é só não
538
+ DEVOLVER: com um `session.put(sessionKey, …)` cru, o refresh token do ator
539
+ continuava serializado no cookie de sessão da identidade nova até a sessão
540
+ expirar. Não devolver e não guardar são coisas diferentes, e é a segunda que
541
+ sustenta a invariante — a credencial parqueada nunca sobrevive à sessão que a
542
+ parqueou. Aplicações que escrevem o token set em `sessionKey` por conta própria
543
+ num fluxo de login devem chamar `startSession()` no lugar.
544
+
545
+ **Limite honesto**, também no docblock: quem controla o cookie jar DURANTE uma
546
+ impersonação ativa continua indistinguível do ator — é literalmente a mesma
547
+ sessão. Isso é o modelo de sessão, não esta conferência. O que fecha é a janela
548
+ em que a credencial sobrevive à sessão que a guardou.
549
+
550
+ **O que acontece no upgrade.** Uma sessão parqueada por uma versão anterior não
551
+ tem vínculo nenhum — é exatamente a credencial que não dá para atribuir.
552
+ `stopImpersonating()` a **recusa e descarta**, e limpa o token set da sessão. Na
553
+ prática: **todo admin que estiver impersonando alguém no momento do deploy é
554
+ deslogado e precisa entrar de novo.** Nenhum outro usuário é afetado, e não
555
+ sobra nada a fazer depois do primeiro ciclo de requests.
556
+
557
+ A alternativa (restaurar uma vez com aviso) foi descartada: seria devolver
558
+ justamente a credencial deste aviso a justamente a parte que não conseguimos
559
+ identificar, e num cookie session store "uma vez" é por cookie jar — o atacante
560
+ também ganharia a dele. O custo do fail-closed é um login de admin; o da
561
+ leniência é manter o furo aberto por uma sessão inteira.
562
+
563
+ **API.** Nada removido. Novo `AuthkitClientManager.endSession(ctx)` (use no
564
+ lugar de `session.forget(sessionKey)` se o seu app derruba a sessão à mão) e
565
+ novo campo opcional `TokenSet.impersonationBinding` — gerenciado pela lib; não
566
+ escreva nele. Se o seu app escreve o TokenSet direto no `sessionKey` (ex.: um
567
+ refresh próprio), preserve esse campo, senão um stop legítimo será recusado
568
+ (fail-closed: o ator é deslogado, não travado).
569
+
570
+ ## 0.15.0
571
+
572
+ ### Minor Changes
573
+
574
+ - 618d83f: `authkitClientGuard()`: um guard de verdade do `@adonisjs/auth` (opt-in)
575
+
576
+ Até agora o `authkit-client` não tinha guard nenhum, e o `authkit_middleware`
577
+ ainda **atropelava** o `ctx.auth` do framework com o `Authenticator` da lib. Um
578
+ host em cima do `authkit-client` simplesmente não conseguia usar `@adonisjs/auth`:
579
+ sem `middleware.auth()`, sem `ctx.auth.user` tipado com o model do app, sem
580
+ Bouncer em cima do usuário logado. Cada host reescrevia o próprio middleware de
581
+ autenticação — e cada um desses é um lugar a mais para errar autorização.
582
+
583
+ **Nada muda para quem já usa a lib.** Sem guard em `config/auth.ts`, o
584
+ `authkit_middleware` continua idêntico: `ctx.auth` segue sendo o `Authenticator`
585
+ do authkit, `getIdentity()` / `getUser()` / `getUserOrFail()` / `hasGlobalRole()`
586
+ / `toSharedProps()` seguem com o mesmo comportamento, e o `auth_middleware` /
587
+ `silent_auth_middleware` continuam funcionando. Não há deprecação, não há aviso
588
+ em runtime, não é preciso migrar.
589
+
590
+ ## O que entrou
591
+
592
+ - `authkitClientGuard({ provider })` — implementa o `GuardContract` do
593
+ `@adonisjs/auth` (mesmo `authenticate()` / `check()` / `getUserOrFail()`, e o
594
+ MESMO `E_UNAUTHORIZED_ACCESS` dos guards nativos, então o `middleware.auth()` e
595
+ o exception handler do host tratam igual).
596
+ - `AuthkitContextMiddleware` (`@adonis-agora/authkit-client/authkit_context_middleware`)
597
+ — popula `ctx.authkit` **sem tocar em `ctx.auth`**.
598
+ - `getAuthkit(ctx)` — o resolvedor memoizado por request que os dois usam.
599
+
600
+ O guard **não reimplementa resolução de sessão**. Ele passa pelo
601
+ `AuthkitClientManager` exatamente como o `authkit_middleware`: refresh proativo
602
+ do token (`maybeRefresh`), o `SessionResolver` configurado (JWT/opaco/PAT),
603
+ as métricas e a ponte do `@agora/context` continuam valendo no caminho do guard.
604
+ A única coisa que ele acrescenta é a ponte: pega `identity.userId` (a claim
605
+ `sub` — a `Identity` **não** tem `id`) e pede o usuário do app ao `provider`.
606
+
607
+ `@adonisjs/auth` é um **peer opcional**: todo import dele é type-only, exceto um
608
+ `await import('@adonisjs/auth')` dentro do resolver do config — que só roda
609
+ quando o host resolve o `config/auth.ts`. Quem não usa `@adonisjs/auth` não
610
+ carrega nada a mais.
611
+
612
+ ## Como habilitar (3 passos)
613
+
614
+ 1. `config/auth.ts`:
615
+
616
+ ```ts
617
+ import { defineConfig } from "@adonisjs/auth";
618
+ import { sessionUserProvider } from "@adonisjs/auth/session";
619
+ import { authkitClientGuard } from "@adonis-agora/authkit-client";
620
+
621
+ export default defineConfig({
622
+ default: "web",
623
+ guards: {
624
+ web: authkitClientGuard({
625
+ provider: sessionUserProvider({
626
+ model: () => import("#models/user"),
627
+ }),
628
+ }),
629
+ },
630
+ });
631
+ ```
632
+
633
+ A coluna de id do model precisa casar com `identity.userId` (é o que o
634
+ `lucidMirror()` grava).
635
+
636
+ 2. `start/kernel.ts`: **troque** o `authkit_middleware` pelo par do framework +
637
+ o middleware de contexto do authkit. Os dois donos de `ctx.auth` não convivem
638
+ na mesma request — é ou um ou outro, de propósito:
639
+
640
+ ```diff
641
+ router.use([
642
+ - () => import('@adonis-agora/authkit-client/authkit_middleware'),
643
+ + () => import('@adonisjs/auth/initialize_auth_middleware'),
644
+ + () => import('@adonis-agora/authkit-client/authkit_context_middleware'),
645
+ ])
646
+ ```
647
+
648
+ Registrar os dois resolveria a sessão duas vezes em objetos diferentes — não
649
+ faça isso.
650
+
651
+ 3. Nas rotas, use o `middleware.auth()` do framework no lugar do
652
+ `auth_middleware` / `silent_auth_middleware` da lib (que passam a ser o
653
+ caminho legado — continuam existindo e funcionando para quem NÃO adotou o
654
+ guard).
655
+
656
+ Depois disso:
657
+
658
+ - `ctx.auth.user` é o model do app, vindo do `provider`;
659
+ - `ctx.authkit` é o `Authenticator` do authkit — `hasGlobalRole()`,
660
+ `getIdentity()` (a `Identity` crua), `toSharedProps()`.
661
+
662
+ ## `provider` + `resolveUser`
663
+
664
+ São superfícies separadas e ambas continuam valendo:
665
+ `ctx.auth.user` vem **sempre** do `provider`; `ctx.authkit.getUser()` continua
666
+ vindo do `resolveUser` de `config/authkit_client.ts`. **O guard nunca chama
667
+ `resolveUser`.** Com o guard configurado, o normal é apagar o `resolveUser` e
668
+ deixar só o `provider`.
669
+
670
+ ## Limitação conhecida
671
+
672
+ `authenticateAsClient()` (o `loginAs` dos plugins de teste do `@adonisjs/auth`)
673
+ lança: a sessão deste guard é um TokenSet OIDC assinado pelo IdP, e a lib não
674
+ tem como forjar um `id_token` a partir de um objeto de usuário. Em teste, use
675
+ `mintTestIdToken()` de `@adonis-agora/authkit-testing` e plante o TokenSet na
676
+ sessão, ou injete `fakeAuthenticator()` em `ctx.authkit`.
677
+
678
+ ## 0.14.0
679
+
680
+ ### Minor Changes
681
+
682
+ - 4a3be7a: Adiciona o acessor singleton `@adonis-agora/authkit-client/services/main` (convenção `services/main` do
683
+ Adonis, como `db`/`mail`/`drive`). Deixa o app usar
684
+ `import authkit from "@adonis-agora/authkit-client/services/main"` e ler `authkit.clientConfig` / chamar
685
+ `authkit.getIdToken(ctx)`, `authkit.handleBackchannelLogout(ctx)` etc., em vez de resolver a binding
686
+ string-keyed `"authkit.client"` pelo container na mão (`ctx.containerResolver.make("authkit.client")`).
687
+ Funciona tanto em controllers-classe quanto em route handlers inline.
688
+
689
+ ## 0.13.0
690
+
691
+ ### Minor Changes
692
+
693
+ - 960f39e: `Authenticator.getUserOrFail(): Promise<TUser>` — o usuário autenticado NÃO-nulo, fail-closed (lança quando não há sessão ou `resolveUser` não devolve usuário). Espelha `authenticate()` (que devolve a `Identity`); este devolve o usuário do app.
694
+
695
+ Substitui o wrapper `currentUser(auth)` que cada app reescrevia sobre `getUser()`:
696
+
697
+ ```ts
698
+ // antes (helper por app):
699
+ const user = await currentUser(auth);
700
+ // agora:
701
+ const user = await auth.getUserOrFail();
702
+ ```
703
+
704
+ Com o generic na augmentation (`auth: Authenticator<AppUser>`), devolve `AppUser` direto, sem cast. Para rotas com visitante, siga usando `getUser()` (`TUser | null`).
705
+
706
+ ## 0.12.0
707
+
708
+ ### Minor Changes
709
+
710
+ - c016a62: `Authenticator` agora é genérico no tipo do usuário do app: `Authenticator<TUser = unknown>`, com `getUser(): Promise<TUser | null>` e `toSharedProps().user: TUser | null`. Non-breaking (default `unknown` mantém o comportamento anterior). Um app fixa o tipo augmentando `HttpContext.auth` (`auth: Authenticator<AppUser>`) e aí `getUser()` devolve `AppUser | null` em todo call-site — acaba o `(await auth.getUser()) as AppUser` repetido. A asserção do model do app fica UMA vez, dentro de `getUser`, em vez de espalhada.
711
+
712
+ ## 0.11.0
713
+
714
+ ### Minor Changes
715
+
716
+ - c12bac9: `authkit-client` now only authenticates — app-role/authorization concerns moved out to
717
+ `@adonis-agora/authz`.
718
+
719
+ Removed:
720
+
721
+ - `AuthenticatorDeps.resolveAppRoles`, `Authenticator.hasAppRole`/`getAppRoles`.
722
+ - `appRoles`/`abilities` from `Authenticator.toSharedProps()` — it now returns
723
+ `{ user, globalRoles }`.
724
+ - `ClientConfigInput.resolveAppRoles`/`ResolvedClientConfig.resolveAppRoles` (`defineConfig`).
725
+ - `AuthMiddlewareOptions.roles`/`unauthorizedRedirect` — the built-in `auth_middleware` now only
726
+ requires a valid session (redirects to `options.redirectTo ?? '/auth/login'` when absent). Use
727
+ `@adonis-agora/authz` (or Bouncer) on the route for role/permission gating.
728
+ - `PostLoginRedirects.byAppRole` in `registerOidcClient` — `byGlobalRole` (claims from the token)
729
+ and `default` still work; the `resolveDestination` helper no longer takes an `authenticator`.
730
+
731
+ Kept: `hasGlobalRole`, `getIdentity` (still populates the Agora context), `getUser`,
732
+ `authenticate`, `check` — these read from the token/session, not from app-defined roles.
733
+
734
+ ## 0.10.1
735
+
736
+ ### Patch Changes
737
+
738
+ - 70f5721: Ship peer dependencies as ranges instead of exact versions
739
+
740
+ `peerDependencies` pointed at the pinned `adonis`/`frontend` catalogs, and pnpm
741
+ inlines a catalog's literal value at publish time — so every published peer came
742
+ out exact. `@adonis-agora/authkit-server@0.34.1` on npm requires
743
+ `"@adonisjs/core": "7.3.3"`, which no app on 7.3.5 can satisfy;
744
+ `@adonis-agora/authkit-react@0.13.0` requires `"react": "19.2.6"`, which locks
745
+ out every consumer not on that exact patch.
746
+
747
+ Peers now resolve from three new range-only catalogs (`adonisPeers`,
748
+ `frontendPeers`, `miscPeers`). Dependencies keep the pinned catalogs — a pin is
749
+ right for reproducible installs and wrong for consumer compatibility, and the
750
+ two were sharing one source.
751
+
752
+ No source or runtime behaviour changes.
753
+
754
+ ## 0.10.0
755
+
756
+ ### Minor Changes
757
+
758
+ - 12df185: Write `globalRoles` into the @agora context from the resolved session (so the Authz global-role bridge can read them), and add Authz permission gating to authkit-react: `useCan(permission, resource?)` and `<CanPermission>`, which consult the Authz `POST <canPath>` endpoint (`{ permission, resource? }` → `{ allowed }`, credentials included) with in-memory caching/dedupe. The endpoint path is configurable via `AuthkitProvider` (`canPath` / `endpoints.can`, default `/authz/can`).
759
+
760
+ ## 0.9.0
761
+
762
+ ### Minor Changes
763
+
764
+ - 394b9aa: Bridge audit events to the @agora diagnostics bus; populate @agora context from the resolved session
765
+ - 0542665: Re-scope to @adonis-agora/authkit-\* (join the Agora ecosystem)
766
+ - 08e721e: Optional resilience policy for outbound OIDC/JWKS calls
767
+
768
+ ### Patch Changes
769
+
770
+ - Updated dependencies [0542665]
771
+ - @adonis-agora/authkit-core@0.7.0
772
+
773
+ ## 0.8.0
774
+
775
+ ### Minor Changes
776
+
777
+ - dd80bb8: Segurança (least privilege): a claim de papéis globais e as claims de organização saem do scope `profile` para um scope dedicado `roles`, e sua emissão é gated a clients first-party (`branding.firstParty`). Clients third-party NÃO recebem papéis/org, mesmo solicitando o scope `roles`. O default de scopes do authkit-client passa a incluir `roles` (consumidores first-party continuam recebendo papéis sem mudança de comportamento). BREAKING para quem dependia de papéis no scope `profile`: o client precisa solicitar o scope `roles`.
778
+
779
+ ## 0.7.2
780
+
781
+ ### Patch Changes
782
+
783
+ - Updated dependencies [93eaf69]
784
+ - Updated dependencies [e2582b8]
785
+ - @adonis-agora/authkit-core@0.6.0
786
+
787
+ ## 0.7.1
788
+
789
+ ### Patch Changes
790
+
791
+ - Updated dependencies [df4b41f]
792
+ - @adonis-agora/authkit-core@0.5.0
793
+
794
+ ## 0.7.0
795
+
796
+ ### Minor Changes
797
+
798
+ - 68a8f4c: `lucidRevocationStore` agora faz auto-prune — limpeza vem da lib, não do app
799
+
800
+ Antes, o app precisava agendar o `prune()` das revogações de back-channel logout
801
+ (scheduler/job). Agora o `lucidRevocationStore` limpa sozinho: no `revoke()`, de
802
+ forma OPORTUNÍSTICA e throttled (no máx. 1× por `everyHours` por processo, default
803
+ 24h), remove revogações mais velhas que `olderThanDays` (default 35). Best-effort —
804
+ falha não atrapalha o logout.
805
+
806
+ - Default LIGADO; configure via `lucidRevocationStore({ autoPrune: { everyHours, olderThanDays } })`.
807
+ - Desligue com `autoPrune: false` (ex.: se preferir agendar você mesmo).
808
+
809
+ Resultado: o consumidor não precisa mais de nenhum scheduler/job para a limpeza.
810
+
811
+ ## 0.6.0
812
+
813
+ ### Minor Changes
814
+
815
+ - 262eb79: Back-Channel Logout pronto para sessões cookie-based + DX do client
816
+
817
+ Antes, fechar o gap de logout SSO em sessão cookie-based exigia escrever model + service + middleware à mão em cada app (e era fácil esquecer — deixando a sessão válida por até 30 dias após um logout SSO). Agora o AuthKit absorve isso:
818
+
819
+ **`@adonis-agora/authkit-client`**
820
+
821
+ - `lucidRevocationStore({ connection?, table? })` + interface `RevocationStore`: persistência append-only de revogações (sid/sub/revoked_at), sem precisar declarar model.
822
+ - `BackchannelRevocationMiddleware` (subpath `/backchannel_revocation_middleware`): derruba a sessão revogada na próxima request.
823
+ - `defineConfig({ backchannelLogout: { store } })`: deriva o `onBackchannelLogout` e expõe o store ao middleware.
824
+ - `lucidMirror(Model, { sync, preload, injectGlobalRoles })`: factory do `resolveUser` "espelho local".
825
+ - Middlewares prontos `auth_middleware` (com `roles`) e `silent_auth_middleware` (subpaths).
826
+ - `buildAuthorizeUrl({ extraParams })`: anexa `audience`/`prompt`/`login_hint`/etc. sem manipular URL na mão.
827
+ - `Authenticator.toSharedProps()`: `{ user, globalRoles, appRoles, abilities }` pronto p/ Inertia share.
828
+ - `AuthkitClientManager.impersonate()` / `stopImpersonating()` / `isImpersonating()`: ciclo de impersonação (RFC 8693) gerenciado.
829
+ - `registerOidcClient(router, { redirects, afterLogin, loginMiddleware })`: registra login/callback/logout (+back-channel) absorvendo PKCE/state/exchange/redirect-por-papel do OidcSessionController.
830
+
831
+ **`@adonis-agora/authkit-server`**
832
+
833
+ - Tabela `auth_session_revocations` gerenciada pelo `ensureAuthkitSchema()` (schema auto-manage) — compartilhável entre apps no mesmo banco.
834
+ - Revogação em massa do admin (`AdminSessionsService.revokeAll`) grava uma revogação `sub` na tabela compartilhada → logout INSTANTÂNEO nos clients cookie-based (antes esperava o refresh token falhar, ~TTL do access token).
835
+ - **Config locks (BREAKING semântico):** settings definidas no `defineConfig` ficam TRAVADAS — config vence e a UI/Admin API não pode alterá-las (`getSetting` → null p/ resolvers caírem no config; `setSetting`/`deleteSetting` → 423 `SettingLockedError`). O console mostra badge "definido via config" e desabilita o controle. Exports: `isSettingLocked`, `lockedSettingKeys`, `deriveLockedSettingKeys`, `SettingLockedError`.
836
+ - **`encrypter` do TOTP agora é DEFAULT (BREAKING):** `lucidAccountStore` encripta o segredo TOTP com `APP_KEY` por padrão (`appKeyEncrypter()`); `encrypter: false` desliga. ⚠️ Segredos gravados em claro por versões anteriores deixam de decriptar — migre ou passe `false`.
837
+ - `jwks: 'auto'` — resolve env-aware (`AUTHKIT_JWKS` inline, senão managed em arquivo); elimina o ternário no config.
838
+ - `adminApi.apiKeys: 'env'` (lê `AUTHKIT_ADMIN_API_KEY`) + `enabled` auto quando há key — elimina o spread condicional.
839
+ - `lucidStores({ account, pat, audit, providerIdentity, webauthnCredential, organizations }, { mfaIssuer, webauthn })`: monta os stores declarando mfaIssuer/webauthn UMA vez.
840
+ - `defineConfig` reusa `mfaIssuer`/`webauthn` do `lucidAccountStore` quando o top-level não os fornece (declare uma vez).
841
+ - `authkitCsrfExceptions(url, { mountPath })`: helper de isenção CSRF das rotas machine-to-machine.
842
+ - **`registerAuthHost(router)` sem opts** — lê mountPath/social/rateLimit/admin/adminApi do `config/authkit.ts` (stash no boot do provider, que roda antes do preload do routes.ts). Acaba com o drift config↔registerAuthHost; `opts` viram só override (ex.: `{ admin: { prefix } }`). Fallback p/ defaults quando não há stash (testes).
843
+
844
+ ## 0.5.0
845
+
846
+ ### Minor Changes
847
+
848
+ - a6ca8a7: Bring your own IdP — use AuthKit against any OIDC-compliant provider
849
+ - **client**: new `discoverEndpoints(issuer)` resolves the IdP's real endpoints from `/.well-known/openid-configuration` (cached per issuer, field-level manual overrides, silent fallback to the oidc-provider conventions when the document is unreachable). All flow helpers (`buildAuthorizeUrl`, `exchangeCode`, `refreshTokens`, `exchangeToken`, `buildEndSessionUrl`) now accept explicit endpoint params — Keycloak, Auth0, Okta, Entra et al. work out of the box.
850
+ - **react**: new `idp: 'authkit' | 'external'` config on `AuthkitProvider`. With an external IdP, the components that depend on authkit-server's REST surface (`UserProfile`, `OrganizationSwitcher`, `OrganizationProfile`, `AuthorizedApps`) degrade to `null` instead of calling endpoints that don't exist; sign-in/out, auth state, role gates and the password strength meter keep working.
851
+ - New "Bring your own IdP" docs page tying the two together.
852
+
853
+ ## 0.4.2
854
+
855
+ ### Patch Changes
856
+
857
+ - Updated dependencies
858
+ - @adonis-agora/authkit-core@0.4.0
859
+
860
+ ## 0.4.1
861
+
862
+ ### Patch Changes
863
+
864
+ - Updated dependencies
865
+ - @adonis-agora/authkit-core@0.3.1
866
+
867
+ ## 0.4.0
868
+
869
+ ### Minor Changes
870
+
871
+ - Round 7 — production pack + multi-tenancy:
872
+ - **Organizations (multi-tenancy)**: optional capability-probed tables (`auth_organizations`, `auth_organization_members`, `auth_organization_invitations`), per-org roles (owner/admin/member), email invitations with hashed tokens, active-org session cookie with `org_id`/`org_slug`/`org_role` claims in id_token/userinfo/JWT access tokens, `/account/orgs` page, admin console section, Admin REST API (`/api/authkit/v1/organizations`), SDK `organizations.*` namespace (remote + embedded), React `useOrganizations`/`useOrganization`/`useSwitchOrganization`/`useOrgInvitations` hooks plus `<OrganizationSwitcher />` and `<OrganizationProfile />` components.
873
+ - **LGPD/GDPR compliance**: self-service and admin account deletion with full cascade (sessions, grants, PATs, passkeys, identities, MFA, avatar) and audit anonymization (stable pseudonym), data export endpoint (`GET /account/security/export`), `login.requireVerifiedEmail` gate across password/magic-link/passkey flows, SDK `users.delete()`.
874
+ - **User migration & password hygiene**: transparent lazy password rehash on login, `password.legacyVerifier` hook for foreign hash formats, `authkit:users:import` ace command (JSON/NDJSON, `--dry-run`), configurable `password.policy`, HaveIBeenPwned k-anonymity breach check (fail-safe), React `usePasswordStrength` + `<PasswordStrengthMeter />`.
875
+ - **JWT access tokens (RFC 9068)**: `accessTokens: { format: 'jwt' }` with per-resource overrides, `verifyJwtAccessToken` local validation in the client package, `authkit:keys:rotate` command with grace-period JWKS rotation.
876
+ - **Bot protection**: pluggable vendor-agnostic `botProtection` config (Turnstile/hCaptcha-ready, fail-safe) on login/signup/reset.
877
+ - **New-device login notification**: `notifications.newDeviceEmail` + `mail.onNewDeviceLogin` hook driven by the trusted-device signal.
878
+ - **Console polish**: session context (user-agent/OS/IP/geo via pluggable `resolveGeo`), RFC 8693 impersonation panel (`admin.impersonation`, default off), dashboard with MAU/daily sign-ins, `GET /api/authkit/v1/stats` + SDK `stats()`.
879
+
880
+ ### Patch Changes
881
+
882
+ - Updated dependencies
883
+ - @adonis-agora/authkit-core@0.3.0
884
+
885
+ ## 0.3.0
886
+
887
+ ### Minor Changes
888
+
889
+ - 0c33640: Round 4 — events/webhooks, DPoP client, full e2e harness, polish.
890
+
891
+ **server (minor):** add `events` config — observe every audit event in-process (`onEvent`)
892
+ and/or via an HMAC-signed webhook (`x-authkit-signature: sha256=...`, 5s fire-and-forget,
893
+ never throws into the request path). When set, the resolved `audit` sink becomes a fan-out
894
+ (original sink + onEvent + webhook), preserving the admin `list()` query. Also: a full
895
+ interaction e2e harness driving login → consent → token (plus step-up MFA and device-flow
896
+ variants) through the real host controllers, and English `authkit:doctor` messages. Builds on
897
+ the existing consent/account-console, admin user CRUD, profile self-service, trusted-device,
898
+ and passwordless (magic-link / passkey-first) features.
899
+
900
+ **client (minor):** add DPoP (RFC 9449) proof generation — `generateDpopKeyPair()` (jose
901
+ ES256, exportable JWK) and `createDpopProof({ key, htm, htu, nonce?, accessToken? })` producing
902
+ a signed `dpop+jwt`, plus `dpopJwkThumbprint()`.
903
+
904
+ ## 0.2.1
905
+
906
+ ### Patch Changes
907
+
908
+ - Updated dependencies [1872a30]
909
+ - @adonis-agora/authkit-core@0.2.0
910
+
911
+ ## 0.2.0
912
+
913
+ ### Minor Changes
914
+
915
+ - Refactors do code review (comportamento preservado, contratos mais limpos):
916
+
917
+ **server (minor):**
918
+
919
+ - `AccountStore` decomposto em interfaces de capacidade (`CoreAccountStore`,
920
+ `MfaCapability`, `WebauthnCapability`, `ProviderIdentityCapability`) com type
921
+ guards (`supportsMfa`/`supportsPasskeys`/`supportsProviderIdentity`). O tipo
922
+ `AccountStore` continua existindo (core & Partial<capacidades>) — compatível.
923
+ `lucidAccountStore` agora OMITE os métodos de capacidades não configuradas em
924
+ vez de lançar em runtime; social login sem provider-identity degrada pro login.
925
+ - Sequência login+lockout centralizada em `attemptPasswordLogin` (era duplicada
926
+ em 2 controllers).
927
+ - `adminGuard` agora retorna 404 quando `admin.enabled: false` (fecha bypass de
928
+ drift entre config e `AuthHostOptions.admin`).
929
+ - `dynamicRegistration.management: true` sem `enabled: true` agora falha no
930
+ resolve do config (RFC 7592 exige 7591).
931
+ - Serialização JSON dos mixins unificada em `jsonColumn()` (semântica por coluna
932
+ preservada).
933
+
934
+ **client (minor):**
935
+
936
+ - POST ao token endpoint unificado (`exchangeCode`/`refreshTokens`/`exchangeToken`).
937
+ - Introspection + claims→Identity compartilhados entre resolvers; `pat`/`opaque`
938
+ agora também mapeiam `picture→profile.avatarUrl` e `sid→sessionId` (alinhados
939
+ ao `jwt`).
940
+
941
+ **react (patch):**
942
+
943
+ - Helpers genéricos de roles; warn de dev no `useAuth` quando não há
944
+ `AuthProvider` nem shared prop do Inertia.
945
+
946
+ ## 0.1.1
947
+
948
+ ### Patch Changes
949
+
950
+ - Corrige os stubs de scaffolding (`node ace configure`):
951
+ - Usa os nomes renomeados dos pacotes (`@adonis-agora/authkit-*`) — antes os
952
+ stubs ainda importavam de `@authkit/*` (inexistente), gerando código quebrado.
953
+ - O model `AuthUser` scaffoldado passa a usar a **conexão default da aplicação**
954
+ (config/database.ts) por padrão, em vez de forçar `static connection = 'auth'`.
955
+ Para isolar o AuthKit num schema/banco dedicado, basta definir a conexão no
956
+ model — documentado no próprio stub. A lib cria as tabelas no banco do app, ou
957
+ onde o dev definir.