@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.
- package/CHANGELOG.md +957 -0
- package/README.md +47 -12
- package/build/auth.d.ts +2 -0
- package/build/auth.js +1 -0
- package/build/authkit_context_middleware.d.ts +1 -0
- package/build/authkit_context_middleware.js +2 -0
- package/build/commands/configure.d.ts +10 -0
- package/build/commands/configure.js +57 -2
- package/build/index.d.ts +3 -2
- package/build/index.js +1 -1
- package/build/providers/authkit_client_provider.d.ts +8 -1
- package/build/providers/authkit_client_provider.js +28 -12
- package/build/src/authenticator.d.ts +4 -3
- package/build/src/authenticator.js +6 -3
- package/build/src/host/authkit_client_guard.d.ts +51 -36
- package/build/src/host/authkit_client_guard.js +97 -46
- package/build/src/host/dashboard_guard.d.ts +3 -7
- package/build/src/host/dashboard_guard.js +3 -7
- package/build/src/host/request_authenticator.d.ts +28 -10
- package/build/src/host/request_authenticator.js +5 -3
- package/build/src/middleware/authkit_context_middleware.d.ts +3 -4
- package/build/src/middleware/authkit_context_middleware.js +5 -4
- package/build/src/middleware/backchannel_revocation_middleware.d.ts +1 -1
- package/build/src/middleware/backchannel_revocation_middleware.js +1 -1
- package/build/src/middleware/require_org_middleware.d.ts +3 -2
- package/build/src/middleware/require_org_middleware.js +5 -4
- package/build/src/resolvers/dpop_proof.d.ts +34 -0
- package/build/src/resolvers/dpop_proof.js +92 -0
- package/build/src/resolvers/factory.d.ts +5 -0
- package/build/src/resolvers/factory.js +1 -0
- package/build/src/resolvers/jwt_resolver.d.ts +9 -0
- package/build/src/resolvers/jwt_resolver.js +47 -3
- package/build/stubs/config/auth.stub +30 -0
- package/build/stubs/config/authkit_client.stub +2 -1
- package/build/stubs/middleware/auth_middleware.stub +25 -0
- package/build/stubs/middleware/silent_auth_middleware.stub +16 -0
- package/build/types.d.ts +5 -32
- package/build/types.js +1 -1
- package/package.json +12 -17
- package/skills/authkit-rp-client/SKILL.md +102 -47
- package/stubs/config/auth.stub +30 -0
- package/stubs/config/authkit_client.stub +2 -1
- package/stubs/middleware/auth_middleware.stub +25 -0
- package/stubs/middleware/silent_auth_middleware.stub +16 -0
- package/build/src/host/ctx_auth.d.ts +0 -6
- package/build/src/host/ctx_auth.js +0 -8
- package/build/src/middleware/auth_middleware.d.ts +0 -13
- package/build/src/middleware/auth_middleware.js +0 -13
- package/build/src/middleware/authkit_middleware.d.ts +0 -6
- package/build/src/middleware/authkit_middleware.js +0 -24
- package/build/src/middleware/silent_auth_middleware.d.ts +0 -13
- 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.
|