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