@adonis-agora/authkit-server 0.59.0 → 0.61.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/build/index.d.ts +4 -2
- package/build/index.js +3 -1
- package/build/providers/authkit_server_provider.js +7 -0
- package/build/src/accounts/account_store.d.ts +20 -1
- package/build/src/accounts/account_store.js +4 -0
- package/build/src/accounts/lucid_account_store.js +4 -0
- package/build/src/accounts/lucid_store/login_methods.d.ts +11 -0
- package/build/src/accounts/lucid_store/login_methods.js +32 -0
- package/build/src/define_config.d.ts +23 -0
- package/build/src/define_config.js +6 -0
- package/build/src/host/account_api/account_api_controller.d.ts +38 -0
- package/build/src/host/account_api/account_api_controller.js +84 -3
- package/build/src/host/auth_host_config.d.ts +9 -0
- package/build/src/host/controllers/headless_login_methods_controller.d.ts +31 -0
- package/build/src/host/controllers/headless_login_methods_controller.js +79 -0
- package/build/src/host/controllers/interaction_controller.js +159 -12
- package/build/src/host/controllers/social_controller.js +29 -1
- package/build/src/host/login_methods_state.d.ts +39 -0
- package/build/src/host/login_methods_state.js +52 -0
- package/build/src/host/register_auth_host.js +18 -0
- package/build/src/host/ui-dist/assets/{index-6cE5JMyP.js → index-Cb38N16r.js} +1 -1
- package/build/src/host/ui-dist/index.html +1 -1
- package/build/src/host/user_login_methods.d.ts +94 -0
- package/build/src/host/user_login_methods.js +132 -0
- package/package.json +7 -4
- package/skills/authkit-idp-setup/SKILL.md +222 -0
- package/skills/authkit-interactions/SKILL.md +236 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: authkit-interactions
|
|
3
|
+
description: >-
|
|
4
|
+
Implement the host-owned login/consent interaction screens of @adonis-agora/authkit-server.
|
|
5
|
+
Covers oidc-provider's interactions.url redirect to /auth/interaction/:uid, the three
|
|
6
|
+
routes every IdP app must register (show/login/consent on AuthInteractionController),
|
|
7
|
+
`node ace configure --ui=edge|react|headless` presets, the shell-controller +
|
|
8
|
+
service.interactions split (details(ctx), login(ctx,{email,password}), consent(ctx)),
|
|
9
|
+
overriding verifyCredentials in config/authkit.ts, renderers edgeRenderer/inertiaRenderer,
|
|
10
|
+
and end-to-end testing with @adonis-agora/authkit-testing (createTestIdentity,
|
|
11
|
+
mintTestIdToken, serveJwks, fakeAuthenticator). Use when the authorization flow 404s at
|
|
12
|
+
the login screen, wiring custom login UI, plugging an external user base, or testing
|
|
13
|
+
OIDC flows without booting an IdP.
|
|
14
|
+
license: MIT
|
|
15
|
+
metadata:
|
|
16
|
+
type: core
|
|
17
|
+
library: "@adonis-agora/authkit-server"
|
|
18
|
+
library_version: "0.60.0"
|
|
19
|
+
framework: adonisjs
|
|
20
|
+
sources:
|
|
21
|
+
- "DavideCarvalho/adonis-authkit:packages/authkit-server/README.md"
|
|
22
|
+
- "DavideCarvalho/adonis-authkit:packages/authkit-server/src/host/renderers/inertia_renderer.ts"
|
|
23
|
+
- "DavideCarvalho/adonis-authkit:packages/authkit-server/src/define_config.ts"
|
|
24
|
+
- "DavideCarvalho/adonis-authkit:packages/authkit-testing/README.md"
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
# Login & consent screens (interactions)
|
|
28
|
+
|
|
29
|
+
When `oidc-provider` meets an unauthenticated user it redirects to
|
|
30
|
+
`interactions.url` (`/auth/interaction/:uid`). Those screens are **yours** — the kit
|
|
31
|
+
ejects a controller shell via `node ace configure` and you register the routes that
|
|
32
|
+
point at it. Without them the authorization code flow dies with a 404 exactly when
|
|
33
|
+
the user should log in.
|
|
34
|
+
|
|
35
|
+
## Setup
|
|
36
|
+
|
|
37
|
+
Pick a UI preset when configuring (asks interactively if omitted):
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
node ace configure @adonis-agora/authkit-server --ui=edge
|
|
41
|
+
# values: edge | react | headless
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Each preset publishes `app/controllers/auth_interaction_controller.ts`; `edge` adds
|
|
45
|
+
Edge views, `react` adds Inertia pages (validating that `@adonisjs/inertia` + Vite +
|
|
46
|
+
React exist first), `headless` returns JSON only. Register the three routes:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
// start/routes.ts
|
|
50
|
+
import router from '@adonisjs/core/services/router'
|
|
51
|
+
import AuthInteractionController from '#controllers/auth_interaction_controller'
|
|
52
|
+
|
|
53
|
+
router.get('/auth/interaction/:uid', [AuthInteractionController, 'show'])
|
|
54
|
+
router.post('/auth/interaction/:uid/login', [AuthInteractionController, 'login'])
|
|
55
|
+
router.post('/auth/interaction/:uid/consent', [AuthInteractionController, 'consent'])
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Source: `packages/authkit-server/README.md` § Rotas de interaction.
|
|
59
|
+
|
|
60
|
+
## Core patterns
|
|
61
|
+
|
|
62
|
+
### Pattern 1 — edit the shell, keep logic in `service.interactions`
|
|
63
|
+
|
|
64
|
+
In all presets the ejected controller is a thin shell: the logic lives in
|
|
65
|
+
`service.interactions`, resolved via `containerResolver.make('authkit.server')`.
|
|
66
|
+
It exposes `details(ctx)` (the prompt + params), `login(ctx, { email, password })`
|
|
67
|
+
and `consent(ctx)`. You only edit the render/redirect parts:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
// headless preset flavor — show() returns JSON, you build your own front
|
|
71
|
+
async show({ request, response }) {
|
|
72
|
+
const service = await this.ctx.containerResolver.make('authkit.server')
|
|
73
|
+
const details = await service.interactions.details(this.ctx)
|
|
74
|
+
return response.json({ uid: request.param('uid'), prompt: details.prompt, params: details.params })
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Keep validation, MFA prompts and grant bookkeeping inside `service.interactions`;
|
|
79
|
+
the shell only translates between HTTP and those calls.
|
|
80
|
+
|
|
81
|
+
Source: `packages/authkit-server/README.md` § UI de login/consent ("o controller
|
|
82
|
+
ejetado é casca: a lógica vive em `service.interactions`").
|
|
83
|
+
|
|
84
|
+
### Pattern 2 — plug your user base via `verifyCredentials`
|
|
85
|
+
|
|
86
|
+
`verifyCredentials` in `config/authkit.ts` decides whether credentials are valid;
|
|
87
|
+
`service.interactions.login` calls it. The default queries the `AuthUser` model by
|
|
88
|
+
email and uses `verifyPassword` — override to authenticate against anything else:
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
// config/authkit.ts
|
|
92
|
+
defineConfig({
|
|
93
|
+
issuer: env.get('AUTHKIT_ISSUER'),
|
|
94
|
+
adapter: adapters.redis({ connection: 'main' }),
|
|
95
|
+
accountStore: lucidAccountStore(AuthUser),
|
|
96
|
+
verifyCredentials: async (email, password) => {
|
|
97
|
+
// Return the account on success; throw/falsy paths fail the login.
|
|
98
|
+
const account = await AuthUser.query().where('email', email).first()
|
|
99
|
+
if (!account) throw new Error('Invalid credentials')
|
|
100
|
+
await verifyPassword(account.passwordHash, password)
|
|
101
|
+
return account
|
|
102
|
+
},
|
|
103
|
+
})
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Whatever it returns must be the same identity surface the configured
|
|
107
|
+
`accountStore` serves, or downstream `findAccount` lookups diverge from what just
|
|
108
|
+
logged in.
|
|
109
|
+
|
|
110
|
+
Source: `packages/authkit-server/README.md` § UI de login/consent (verifyCredentials),
|
|
111
|
+
`src/define_config.ts` (`accountStore` derives findAccount/verifyCredentials).
|
|
112
|
+
|
|
113
|
+
### Pattern 3 — custom rendering with `inertiaRenderer`
|
|
114
|
+
|
|
115
|
+
Hosts building their own React screens set the `render` option instead of relying
|
|
116
|
+
on the default Edge renderer:
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
import { defineConfig, inertiaRenderer } from '@adonis-agora/authkit-server'
|
|
120
|
+
|
|
121
|
+
defineConfig({
|
|
122
|
+
issuer: env.get('AUTHKIT_ISSUER'),
|
|
123
|
+
adapter: adapters.database(),
|
|
124
|
+
accountStore: lucidAccountStore(AuthUser),
|
|
125
|
+
render: inertiaRenderer(), // renders Inertia pages for /account/* and /auth/interaction/*
|
|
126
|
+
})
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Without any renderer, every `/account/*` and `/auth/interaction/*` request fails
|
|
130
|
+
with an unexplained 500 (`render` is undefined).
|
|
131
|
+
|
|
132
|
+
Source: `src/define_config.ts` (`render` JSDoc), `index.ts` exports
|
|
133
|
+
(`inertiaRenderer`, `edgeRenderer`).
|
|
134
|
+
|
|
135
|
+
### Pattern 4 — test flows without booting an IdP
|
|
136
|
+
|
|
137
|
+
`@adonis-agora/authkit-testing` mints real signed ID tokens validated by a local
|
|
138
|
+
JWKS, and fakes the authenticator for controller tests:
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
import { mintTestIdToken, serveJwks, fakeAuthenticator } from '@adonis-agora/authkit-testing'
|
|
142
|
+
import { resolvers } from '@adonis-agora/authkit-client'
|
|
143
|
+
|
|
144
|
+
const { token, jwks } = await mintTestIdToken({
|
|
145
|
+
issuer: 'https://idp.test',
|
|
146
|
+
clientId: 'my-app',
|
|
147
|
+
claims: { sub: 'user-42', email: 'jane@test.dev', roles: ['ADMIN'] },
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
const served = await serveJwks(jwks)
|
|
151
|
+
const factory = resolvers.jwt({ jwksUri: served.jwksUri })
|
|
152
|
+
const resolver = await factory.resolver({
|
|
153
|
+
issuer: 'https://idp.test',
|
|
154
|
+
clientId: 'my-app',
|
|
155
|
+
sessionKey: 'authkit',
|
|
156
|
+
globalRolesClaim: 'roles',
|
|
157
|
+
})
|
|
158
|
+
const ctx = { auth: fakeAuthenticator({ identity: null }) } // anonymous request fake
|
|
159
|
+
await served.close()
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Also available: `createTestIdentity(overrides?)` for valid `Identity` defaults,
|
|
163
|
+
`fakeAccountStore({ withMfa: true, ... })` for capability-probed store fakes.
|
|
164
|
+
|
|
165
|
+
Source: `packages/authkit-testing/README.md`.
|
|
166
|
+
|
|
167
|
+
## Common mistakes
|
|
168
|
+
|
|
169
|
+
### CRITICAL — Forgetting to register the interaction routes
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
// Wrong — only the protocol endpoints exist
|
|
173
|
+
registerOidcRoutes(router)
|
|
174
|
+
// no GET /auth/interaction/:uid anywhere
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
// Correct — the three host-owned routes are registered next to the OIDC mount
|
|
179
|
+
registerOidcRoutes(router)
|
|
180
|
+
router.get('/auth/interaction/:uid', [AuthInteractionController, 'show'])
|
|
181
|
+
router.post('/auth/interaction/:uid/login', [AuthInteractionController, 'login'])
|
|
182
|
+
router.post('/auth/interaction/:uid/consent', [AuthInteractionController, 'consent'])
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Nothing crashes at boot; the failure surfaces mid-flow — the user's browser lands
|
|
186
|
+
on `/auth/interaction/:uid` and gets a 404, so no client can ever complete login.
|
|
187
|
+
|
|
188
|
+
Source: `packages/authkit-server/README.md` § Rotas de interaction ("Sem essas rotas
|
|
189
|
+
o fluxo de autorização cai num 404 ao chegar na tela de login").
|
|
190
|
+
|
|
191
|
+
### HIGH — Writing login/consent logic inside the ejected controller shell
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
// Wrong — reimplementing prompt handling/grants in the ejected shell
|
|
195
|
+
async consent(ctx) {
|
|
196
|
+
// hand-rolling grant persistence against oidc-provider internals...
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
// Correct — shell delegates; the service owns the flow
|
|
202
|
+
async consent(ctx) {
|
|
203
|
+
const service = await ctx.containerResolver.make('authkit.server')
|
|
204
|
+
await service.interactions.consent(ctx) // handles the grant, returns the redirect
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
The shell is regenerated by `configure` and has no access to the provider's
|
|
209
|
+
interaction plumbing; duplicating logic there silently drifts from prompt/consent
|
|
210
|
+
semantics the provider expects.
|
|
211
|
+
|
|
212
|
+
Source: `packages/authkit-server/README.md` § UI de login/consent ("Você edita só a
|
|
213
|
+
parte de render/redirect").
|
|
214
|
+
|
|
215
|
+
### MEDIUM — Choosing `--ui=react` without the Inertia stack installed
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
# Wrong — react preset in a bare API-only AdonisJS app
|
|
219
|
+
node ace configure @adonis-agora/authkit-server --ui=react
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
# Correct — match the preset to the app stack
|
|
224
|
+
node ace configure @adonis-agora/authkit-server --ui=edge # server-rendered views
|
|
225
|
+
node ace configure @adonis-agora/authkit-server --ui=headless # build your own front
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
The `react` preset requires `@adonisjs/inertia` + Vite + React in the host app —
|
|
229
|
+
`configure` validates the stack before publishing, so the command aborts instead of
|
|
230
|
+
half-configuring your app.
|
|
231
|
+
|
|
232
|
+
Source: `packages/authkit-server/README.md` § UI de login/consent ("Exige
|
|
233
|
+
@adonisjs/inertia + Vite + React no app — o configure valida essa stack").
|
|
234
|
+
|
|
235
|
+
See also: `authkit-rp-client/SKILL.md` — the consuming side that ends up holding
|
|
236
|
+
the session these screens create.
|