@jskit-ai/agent-docs 0.1.239 → 0.1.241
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/guide/agent/app-extras/assistant-conversation.md +11 -6
- package/guide/agent/app-setup/authentication.md +28 -2
- package/guide/agent/app-setup/existing-application-migration.md +5 -3
- package/guide/agent/app-setup/initial-scaffolding.md +4 -1
- package/guide/agent/app-setup/run-an-accounts-hub.md +152 -0
- package/guide/agent/app-setup/sign-in-through-oidc-issuer.md +148 -0
- package/guide/agent/app-setup/upgrading-jskit.md +13 -0
- package/guide/agent/framework/application-operations.md +3 -0
- package/guide/agent/framework/ui-operations.md +24 -0
- package/guide/agent/index.md +2 -0
- package/package.json +1 -1
- package/patterns/feature-package/example/booking-engine/package.json +1 -1
- package/patterns/minimal-foundation/example/package.json +3 -3
- package/patterns/shell-foundation/example/package.json +4 -4
- package/patterns/shell-foundation/example/packages/main/package.json +1 -1
- package/reference/autogen/KERNEL_MAP.md +1 -0
- package/reference/autogen/PATTERN_INDEX.md +57 -35
- package/reference/autogen/README.md +2 -0
- package/reference/autogen/packages/auth-core.md +1 -0
- package/reference/autogen/packages/auth-provider-oidc-core.md +144 -0
- package/reference/autogen/packages/auth-web.md +16 -0
- package/reference/autogen/packages/kernel.md +6 -1
- package/reference/autogen/packages/oidc-issuer-core.md +201 -0
- package/reference/autogen/packages/shell-web.md +3 -0
- package/reference/autogen/tooling/jskit-release.md +1 -0
- package/skills/jskit/references/app-operations.md +3 -0
- package/skills/jskit/references/existing-application-migration.md +5 -3
- package/skills/jskit/references/pattern-index.md +57 -35
- package/skills/jskit/references/patterns/app/minimal-foundation/example/package.json +3 -3
- package/skills/jskit/references/patterns/app/shell-foundation/example/package.json +4 -4
- package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/package.json +1 -1
- package/skills/jskit/references/patterns/auth/accounts-hub/PATTERN.md +97 -0
- package/skills/jskit/references/patterns/auth/accounts-hub/example/.env.example +10 -0
- package/skills/jskit/references/patterns/auth/accounts-hub/example/package.json +8 -0
- package/skills/jskit/references/patterns/auth/accounts-hub/example/server/hubPaths.js +7 -0
- package/skills/jskit/references/patterns/auth/auth-surface/PATTERN.md +33 -11
- package/skills/jskit/references/patterns/auth/oidc-sign-in/PATTERN.md +87 -0
- package/skills/jskit/references/patterns/auth/oidc-sign-in/example/.env.example +13 -0
- package/skills/jskit/references/patterns/auth/oidc-sign-in/example/package.json +8 -0
- package/skills/jskit/references/patterns/auth/supabase-auth/example/package.json +1 -1
- package/skills/jskit/references/patterns/connectors/calendar-cli/example/package.json +4 -4
- package/skills/jskit/references/patterns/connectors/oauth-connection/PATTERN.md +25 -0
- package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/package.json +2 -2
- package/skills/jskit/references/patterns/database/mysql-application/example/package.json +1 -1
- package/skills/jskit/references/patterns/database/postgres-application/example/package.json +1 -1
- package/skills/jskit/references/patterns/realtime/realtime-application/example/package.json +2 -2
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/package.json +1 -1
- package/skills/jskit/references/patterns/shell/application-shell/PATTERN.md +9 -0
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/package.json +2 -2
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/package.json +3 -3
- package/skills/jskit/references/ui-operations.md +24 -0
|
@@ -485,10 +485,14 @@ and the existing queuing behavior for a runtime that advertises steering.
|
|
|
485
485
|
Applications may opt into `deferWhileWorking: true` with
|
|
486
486
|
`queueWhileSending: true` for a conversation that cannot steer its active turn.
|
|
487
487
|
Typed and retained voice submissions become pending in the original serial
|
|
488
|
-
queue with their exact message ID, text, attachments and captured data.
|
|
489
|
-
existing subscription
|
|
490
|
-
|
|
491
|
-
|
|
488
|
+
queue with their exact message ID, text, attachments and captured data. Each
|
|
489
|
+
waits only while the existing subscription reports a working turn that cannot
|
|
490
|
+
take steering, and its pending status says so ("Pending: Waiting for the
|
|
491
|
+
assistant to finish this step"). When that working turn becomes steerable the
|
|
492
|
+
message is sent as steering, keeping the finished-turn fallback to one ordinary
|
|
493
|
+
Send; when the subscription reports ready it is sent as an ordinary request.
|
|
494
|
+
Normal server permissions still apply at dispatch. Show **Send** and the
|
|
495
|
+
pending status, not **Steer**, when the runtime cannot steer.
|
|
492
496
|
Native steering and explicit retries keep their captured intent. Stop aborts
|
|
493
497
|
these local pre-dispatch followers before stopping the original turn; actor
|
|
494
498
|
retirement and lost access cannot dispatch them later. This option defaults to
|
|
@@ -2850,8 +2854,9 @@ Real account, environment, socket and provider recovery still runs normally.
|
|
|
2850
2854
|
Native compaction remains the engine's job.
|
|
2851
2855
|
JSKIT owns the local history adapter used for model-provider changes. It keeps
|
|
2852
2856
|
native history intact and translates only outgoing requests. For qualified
|
|
2853
|
-
DeepSeek
|
|
2854
|
-
|
|
2857
|
+
models (`codexHistoryRouting`: DeepSeek V4.1 Flash, DeepSeek V4 Pro and GLM 5.3),
|
|
2858
|
+
an OpenAI encrypted compaction is supplemented with the exact readable records
|
|
2859
|
+
from its saved native boundary. Recovery is bounded and
|
|
2855
2860
|
excludes only exact user-message copies retained by that same native boundary
|
|
2856
2861
|
and still present before it in the outgoing request, counting each occurrence.
|
|
2857
2862
|
Unmatched messages, tool results and images retain their original archive order.
|
|
@@ -17,6 +17,13 @@ For Supabase authentication:
|
|
|
17
17
|
npm install @jskit-ai/auth-provider-supabase-core @jskit-ai/auth-web
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
+
To sign in through an accounts hub or another OpenID Connect issuer (see
|
|
21
|
+
[Sign in through an OIDC issuer](/guide/app-setup/sign-in-through-oidc-issuer)):
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @jskit-ai/auth-provider-oidc-core @jskit-ai/auth-web
|
|
25
|
+
```
|
|
26
|
+
|
|
20
27
|
The dependency graph supplies `@jskit-ai/auth-core`. Do not install two
|
|
21
28
|
providers for the same `auth.service` capability.
|
|
22
29
|
|
|
@@ -27,8 +34,27 @@ owns permitted login methods, visible OAuth providers, public routes,
|
|
|
27
34
|
post-login destinations, surface access policy, and secret injection.
|
|
28
35
|
|
|
29
36
|
Use the `auth/auth-surface` pattern for login, sign-out, reset, guards, profile
|
|
30
|
-
placements,
|
|
31
|
-
environment and configuration shape
|
|
37
|
+
placements, HTTP integration, and the managed-preview login. Use
|
|
38
|
+
`auth/supabase-auth` for the Supabase environment and configuration shape, and
|
|
39
|
+
`auth/oidc-sign-in` for an OpenID Connect issuer.
|
|
40
|
+
|
|
41
|
+
## Managed-preview login is standard
|
|
42
|
+
|
|
43
|
+
An application with accounts always includes the managed-preview login, whether
|
|
44
|
+
or not anyone asked for it. Adding authentication adds both parts from the
|
|
45
|
+
`auth/auth-surface` pattern:
|
|
46
|
+
|
|
47
|
+
- the committed, executable `tools/preview-identity` from its example;
|
|
48
|
+
- the `#### Preview identity` block in the web-presented Vibe64 `Outputs`
|
|
49
|
+
target (Command `tools/preview-identity`, Protocol
|
|
50
|
+
`vibe64.preview-identity.command.v1`, Identity types `email` `user-id`,
|
|
51
|
+
Enabled environment `AUTH_DEV_BYPASS_ENABLED`, Secret environment
|
|
52
|
+
`AUTH_DEV_BYPASS_SECRET`, Runtimes `nodejs`), copied exactly from the pattern.
|
|
53
|
+
|
|
54
|
+
The preview host supplies both environment values per run, so a managed
|
|
55
|
+
preview can sign its browser in as an existing account. Which accounts it may
|
|
56
|
+
use stays the person's choice; the application never creates users for it, and
|
|
57
|
+
the exchange is inert without both values.
|
|
32
58
|
|
|
33
59
|
## Server boundary
|
|
34
60
|
|
|
@@ -316,9 +316,11 @@ Do not conflate these identities:
|
|
|
316
316
|
application profile and required workspace membership already exist. It does
|
|
317
317
|
not synthesize any of them as a side effect.
|
|
318
318
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
319
|
+
An application with accounts has the standard managed-preview login: retain
|
|
320
|
+
the app-owned `tools/preview-identity` executable, or add it from
|
|
321
|
+
`auth/auth-surface` when it is missing, and declare it under
|
|
322
|
+
`#### Preview identity` in the web-presented Vibe64 `Outputs` target exactly as
|
|
323
|
+
that pattern shows. JSKIT owns the executable/library pattern, Vibe64 owns
|
|
322
324
|
the declaration's grammar and runtime behavior, and Genesis transports the
|
|
323
325
|
consumer-owned section without interpreting it. The executable calls the
|
|
324
326
|
`@jskit-ai/auth-web` server-side managed-preview library; it does not need a
|
|
@@ -22,7 +22,10 @@ browser-product baseline. It includes:
|
|
|
22
22
|
- responsive JSKIT shell
|
|
23
23
|
- surfaces, placements, topology, and settings
|
|
24
24
|
- lint, unit, client, build, and browser configuration
|
|
25
|
-
|
|
25
|
+
|
|
26
|
+
It has no accounts. Adding authentication through `auth/auth-surface` also adds
|
|
27
|
+
the standard managed-preview login (`tools/preview-identity` and its
|
|
28
|
+
`#### Preview identity` Outputs block).
|
|
26
29
|
|
|
27
30
|
Use it when navigation and settings are real product requirements. Replace its
|
|
28
31
|
home content and vocabulary; do not preserve the concrete `reading-room` name
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
<!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/app-setup/run-an-accounts-hub.md`. Do not edit manually. -->
|
|
2
|
+
|
|
3
|
+
# Run an accounts hub
|
|
4
|
+
|
|
5
|
+
An accounts hub gives one person or company a single sign-in for all of their
|
|
6
|
+
apps. It is an OpenID Connect issuer that runs as its **own** JSKIT project, on a
|
|
7
|
+
domain of its own. Apps sign in through it like they would through Google: the
|
|
8
|
+
hub shows its sign-in page, the app receives an ID token, and the app keeps its
|
|
9
|
+
own session.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @jskit-ai/oidc-issuer-core @jskit-ai/database-runtime-mysql
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Start from the "JSKIT · Accounts hub" template (seed-jskit branch
|
|
16
|
+
`accounts-hub`) when you can: it already has the pages, the Stack and the tests.
|
|
17
|
+
Use the `auth/accounts-hub` pattern for the composition rules. Apps connect with
|
|
18
|
+
`@jskit-ai/auth-provider-oidc-core`; see
|
|
19
|
+
[Sign in through an OIDC issuer](/guide/app-setup/sign-in-through-oidc-issuer).
|
|
20
|
+
|
|
21
|
+
## In order
|
|
22
|
+
|
|
23
|
+
1. Create the hub from the template, with its own database.
|
|
24
|
+
2. Development: set `OIDC_HUB_OWNER_EMAIL` (ask the person), a random
|
|
25
|
+
`OIDC_HUB_REGISTRATION_TOKEN` and, if the database is shared or kept,
|
|
26
|
+
`OIDC_HUB_SECRET`. Start it, create the owner account and confirm it (the
|
|
27
|
+
link is in the server log without a sender). Run the tests.
|
|
28
|
+
3. Production: choose the hub's own domain and set `APP_PUBLIC_URL`, a new
|
|
29
|
+
`OIDC_HUB_SECRET`, the same registration token the apps will use, the owner
|
|
30
|
+
email, an email sender and `OIDC_HUB_DEV_ORIGIN_PATTERNS` for the apps'
|
|
31
|
+
development previews.
|
|
32
|
+
4. Deploy, then sign in as the owner and follow **Setup** until every item is
|
|
33
|
+
ready. Only then connect apps (see [Connecting an app](#connecting-an-app)).
|
|
34
|
+
|
|
35
|
+
Report Setup honestly: do not say email or Google works until its Setup item is
|
|
36
|
+
ready.
|
|
37
|
+
|
|
38
|
+
## What the hub does
|
|
39
|
+
|
|
40
|
+
- **Sign-in for apps.** `/.well-known/openid-configuration` and `/oidc/*` serve a
|
|
41
|
+
hardened `oidc-provider`: authorization code with PKCE only, exact redirect
|
|
42
|
+
URIs, ES256 ID tokens that include `email`, `email_verified` and `name`, no
|
|
43
|
+
refresh tokens for apps, `iss` in every authorization response, RP-initiated
|
|
44
|
+
and back-channel logout.
|
|
45
|
+
- **Accounts.** Email and password (scrypt v1, the same format as JSKIT local
|
|
46
|
+
accounts), email confirmation, password recovery, and optional "Continue with
|
|
47
|
+
Google" with the owner's own Google client. An account reaches apps only once
|
|
48
|
+
its email is confirmed, because apps trust that address. Apps sign in
|
|
49
|
+
silently only while the browser is signed in to the hub as the same person.
|
|
50
|
+
- **Approval.** Apps register themselves at `/oidc/reg` with the registration
|
|
51
|
+
token. Loopback and development addresses are approved automatically; every
|
|
52
|
+
other address waits until the owner clicks Approve on the hub's Apps page.
|
|
53
|
+
- **Admin pages.** Apps (approve, block, remove, rotate the signing key), People
|
|
54
|
+
(turn accounts off, which signs them out of every app through back-channel
|
|
55
|
+
logout) and Setup (a checklist of what is ready).
|
|
56
|
+
|
|
57
|
+
## Environment
|
|
58
|
+
|
|
59
|
+
| Name | Required | Meaning |
|
|
60
|
+
|---|---|---|
|
|
61
|
+
| `APP_PUBLIC_URL` | production | The hub's origin, which is its issuer. https outside this computer, no path. |
|
|
62
|
+
| `OIDC_HUB_SECRET` | production | At least 32 random bytes. Protects cookies and the stored signing keys; never change it once set. Development generates one in `.jskit/oidc-hub/secret`, so set it explicitly whenever the database outlives that folder (a hosted editor, several checkouts sharing one database). |
|
|
63
|
+
| `OIDC_HUB_REGISTRATION_TOKEN` | yes | At least 24 characters. Apps present it to register. Give the same value to each app as `AUTH_OIDC_REGISTRATION_TOKEN`. |
|
|
64
|
+
| `OIDC_HUB_OWNER_EMAIL` | yes | The owner's email. That account, once its email is confirmed, opens the admin pages. |
|
|
65
|
+
| `OIDC_HUB_DEV_ORIGIN_PATTERNS` | no | Comma-separated `https://` origin globs approved automatically, for example `https://preview-*.acme.example.dev`. `*` matches inside one DNS label. Loopback is always approved. |
|
|
66
|
+
| `OIDC_HUB_EMAIL_FROM` with `RESEND_API_KEY` or `SMTP_URL` | production | The owner's own sender. In development, without a sender, emails are written to the server log. |
|
|
67
|
+
| `OIDC_HUB_GOOGLE_CLIENT_ID` and `OIDC_HUB_GOOGLE_CLIENT_SECRET` | no | Turn on "Continue with Google". The Google redirect URI is `{APP_PUBLIC_URL}/hub/google/callback`. |
|
|
68
|
+
|
|
69
|
+
Each problem stops the hub with one sentence that names the variable to fix.
|
|
70
|
+
|
|
71
|
+
## Mounting
|
|
72
|
+
|
|
73
|
+
The installed `OidcIssuerProvider` mounts everything on the app's Fastify
|
|
74
|
+
server. A server that filters paths by surface must also serve the hub's
|
|
75
|
+
paths:
|
|
76
|
+
|
|
77
|
+
```js
|
|
78
|
+
import { HUB_GLOBAL_PATHS } from "@jskit-ai/oidc-issuer-core/server";
|
|
79
|
+
|
|
80
|
+
registerSurfaceRequestConstraint({
|
|
81
|
+
fastify: app,
|
|
82
|
+
surfaceRuntime,
|
|
83
|
+
serverSurface,
|
|
84
|
+
globalUiPaths: [...runtimeGlobalUiPaths, ...HUB_GLOBAL_PATHS]
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The hub's own pages are ordinary Vue pages. They call `/hub/api/*` with
|
|
89
|
+
`x-hub-request: 1` on every state-changing request. An app's sign-in arrives at
|
|
90
|
+
`/hub/interaction/:uid`, which sends the browser to `/auth/sign-in?interaction=…`.
|
|
91
|
+
That page reads `/hub/interaction/:uid/details` (app name, full address and
|
|
92
|
+
status) and finishes with `/hub/interaction/:uid/continue` once the person is
|
|
93
|
+
signed in.
|
|
94
|
+
|
|
95
|
+
## Registration and approval
|
|
96
|
+
|
|
97
|
+
A registration carries only `client_name` (at most 80 characters),
|
|
98
|
+
`redirect_uris`, `post_logout_redirect_uris`, `backchannel_logout_uri`,
|
|
99
|
+
`token_endpoint_auth_method` (`client_secret_basic`), `grant_types`
|
|
100
|
+
(`["authorization_code"]`) and `response_types` (`["code"]`). Every address must
|
|
101
|
+
be on one origin, https unless it is loopback. Anything else is refused with
|
|
102
|
+
`invalid_client_metadata`.
|
|
103
|
+
|
|
104
|
+
| Address | Status |
|
|
105
|
+
|---|---|
|
|
106
|
+
| Loopback, or matching `OIDC_HUB_DEV_ORIGIN_PATTERNS` | `active-dev`: works at once; removed after 30 idle days |
|
|
107
|
+
| An origin the owner already approved | `active` |
|
|
108
|
+
| Any other origin | `pending`: the person sees "This app is waiting for approval by the hub's owner." |
|
|
109
|
+
| A blocked origin | refused with 403 "This address is blocked by the hub's owner." |
|
|
110
|
+
|
|
111
|
+
The response header `x-hub-client-status` tells the registering app its status.
|
|
112
|
+
|
|
113
|
+
## Commands
|
|
114
|
+
|
|
115
|
+
Run them from the hub project's folder; they read its `.env` and database
|
|
116
|
+
settings.
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
npx jskit-oidc-issuer keys rotate
|
|
120
|
+
npx jskit-oidc-issuer import-accounts --in accounts.jsonl # dry run
|
|
121
|
+
npx jskit-oidc-issuer import-accounts --in accounts.jsonl --apply
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
- `keys rotate` makes a new ES256 key active. The previous key keeps verifying
|
|
125
|
+
for two hours, then leaves the JWKS. The Apps page has the same button.
|
|
126
|
+
- `import-accounts` reads the JSON Lines written by
|
|
127
|
+
`jskit-oidc-sign-in export-local-accounts`. It keeps each `usr_` id as the
|
|
128
|
+
hub's `sub` and each scrypt password byte for byte, so people sign in with the
|
|
129
|
+
password they already had. Emails start unconfirmed: each person confirms
|
|
130
|
+
theirs once, at their first app sign-in. Rows that clash with a
|
|
131
|
+
different hub account are refused and listed. A dry run prints only counts.
|
|
132
|
+
- `preview-identity` implements `vibe64.preview-identity.command.v1` for the
|
|
133
|
+
hub, so an editor's preview can sign in as an existing hub account. It works
|
|
134
|
+
only outside production, from loopback, with `AUTH_DEV_BYPASS_ENABLED` and
|
|
135
|
+
`AUTH_DEV_BYPASS_SECRET`.
|
|
136
|
+
|
|
137
|
+
## Connecting an app
|
|
138
|
+
|
|
139
|
+
1. Install `@jskit-ai/auth-provider-oidc-core` in the app.
|
|
140
|
+
2. Give the app `AUTH_OIDC_ISSUER` (the hub's `APP_PUBLIC_URL`) and
|
|
141
|
+
`AUTH_OIDC_REGISTRATION_TOKEN` (the hub's `OIDC_HUB_REGISTRATION_TOKEN`).
|
|
142
|
+
3. Sign in once from the app. A development address works straight away. After
|
|
143
|
+
the app is deployed, open the hub's Apps page and approve it at its full
|
|
144
|
+
address.
|
|
145
|
+
|
|
146
|
+
## Verify
|
|
147
|
+
|
|
148
|
+
- Start the hub with one variable missing and read the sentence it prints.
|
|
149
|
+
- A loopback app registers as `active-dev` and signs in.
|
|
150
|
+
- An https app on another domain waits until Approve, then signs in.
|
|
151
|
+
- Setup shows every item ticked once the owner confirms the domain and sends a
|
|
152
|
+
test email.
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
<!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/app-setup/sign-in-through-oidc-issuer.md`. Do not edit manually. -->
|
|
2
|
+
|
|
3
|
+
# Sign in through an OIDC issuer
|
|
4
|
+
|
|
5
|
+
Use this when an app should not keep its own passwords: people sign in with
|
|
6
|
+
the account they already have in an accounts hub (see
|
|
7
|
+
[Run an accounts hub](/guide/app-setup/run-an-accounts-hub)) or in any OpenID
|
|
8
|
+
Connect issuer, such as Google Workspace or Okta. The app still keeps its own
|
|
9
|
+
`users` rows and its own session; the issuer only proves who the person is.
|
|
10
|
+
|
|
11
|
+
The pattern is `auth/oidc-sign-in`.
|
|
12
|
+
|
|
13
|
+
## In order
|
|
14
|
+
|
|
15
|
+
1. Have the issuer's address and either a registration token (an accounts hub)
|
|
16
|
+
or a client id and secret (any other issuer). Ask the person; never invent them.
|
|
17
|
+
2. Install the provider and run the migration (below).
|
|
18
|
+
3. Set or link the Env values (below) for development and production.
|
|
19
|
+
4. Sign in once in development. Against a hub, a development address works at
|
|
20
|
+
once when it is on this computer or matches the hub's development patterns.
|
|
21
|
+
5. Deploy, then ask the hub's owner to approve the app on the hub's Apps page at
|
|
22
|
+
the app's full address. Until then sign-in shows the hub's waiting page.
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
Replace the local provider; an app has exactly one `auth.service` provider.
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm uninstall @jskit-ai/auth-provider-local-core
|
|
30
|
+
npm install @jskit-ai/auth-provider-oidc-core @jskit-ai/auth-web
|
|
31
|
+
npm run db:migrate
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The migration adds `auth_oidc_clients`, `auth_oidc_sessions` and
|
|
35
|
+
`auth_oidc_logout_tokens`. Existing local tables are left alone; move the
|
|
36
|
+
accounts first (below) if the app already has people.
|
|
37
|
+
|
|
38
|
+
## Env
|
|
39
|
+
|
|
40
|
+
| Name | Meaning |
|
|
41
|
+
|---|---|
|
|
42
|
+
| `AUTH_OIDC_ISSUER` | The issuer address. Its discovery document supplies everything else. |
|
|
43
|
+
| `AUTH_OIDC_REGISTRATION_TOKEN` | Preferred. The app registers itself with the issuer, once per address. |
|
|
44
|
+
| `AUTH_OIDC_CLIENT_ID` / `AUTH_OIDC_CLIENT_SECRET` | For issuers without self-registration. Use these **instead of** the token, never both. |
|
|
45
|
+
| `AUTH_OIDC_LABEL` | Button label. Default "Continue with your account". |
|
|
46
|
+
| `AUTH_OIDC_SESSION_SECRET` | Required in production, at least 32 characters. In development it is generated in `.jskit/auth/oidc-session.secret`. |
|
|
47
|
+
| `APP_PUBLIC_URL` | The address people use. With it the app registers at start; without it, on the first sign-in from a new address. Required in production behind a proxy that is not on the same machine. |
|
|
48
|
+
|
|
49
|
+
Addresses must be `https`, or `http` on `localhost`/loopback. Without
|
|
50
|
+
`AUTH_OIDC_ISSUER` the app still starts; pressing the button brings the person
|
|
51
|
+
back to the login page with "Sign-in is not set up yet: AUTH_OIDC_ISSUER is
|
|
52
|
+
missing." Every sign-in that cannot start is explained there the same way.
|
|
53
|
+
|
|
54
|
+
Never invent either value or copy it into source. If the host keeps saved
|
|
55
|
+
values (an editor's saved keys, a deployment secret store), link these two
|
|
56
|
+
variables to the hub's saved address and token instead of pasting them, in
|
|
57
|
+
development and in production.
|
|
58
|
+
|
|
59
|
+
The issuer must be reachable from the app's server and from the person's
|
|
60
|
+
browser. A hub that runs only on another computer's `localhost` (for example in
|
|
61
|
+
another project's development preview) is not; connect apps to the deployed hub.
|
|
62
|
+
|
|
63
|
+
## What the issuer is told
|
|
64
|
+
|
|
65
|
+
When registering, the app sends:
|
|
66
|
+
|
|
67
|
+
| Field | Value |
|
|
68
|
+
|---|---|
|
|
69
|
+
| `redirect_uris` | `<address>/auth/login` (`AUTH_OIDC_REDIRECT_PATH`) |
|
|
70
|
+
| `post_logout_redirect_uris` | `<address>/` |
|
|
71
|
+
| `backchannel_logout_uri` | `<address>/api/auth/oidc/backchannel-logout` |
|
|
72
|
+
| `token_endpoint_auth_method` | `client_secret_basic` |
|
|
73
|
+
| `grant_types` / `response_types` | `authorization_code` / `code` |
|
|
74
|
+
|
|
75
|
+
Scopes are `openid email profile`. A static client must be registered with the
|
|
76
|
+
same redirect URI.
|
|
77
|
+
|
|
78
|
+
An accounts hub decides what a new address may do. Development addresses work
|
|
79
|
+
at once. A production address waits until the hub's owner approves it on the
|
|
80
|
+
hub's Apps page; until then, signing in shows the hub's own waiting page. A
|
|
81
|
+
blocked address cannot register, and the login page says "Your accounts hub has
|
|
82
|
+
blocked this app's address."
|
|
83
|
+
|
|
84
|
+
## Signing in
|
|
85
|
+
|
|
86
|
+
The login page shows one button. Unframed, it goes to the issuer and comes back
|
|
87
|
+
to `/auth/login`, then to the page the person started from. Inside a frame,
|
|
88
|
+
such as an editor Preview, the issuer cannot be shown, so the button opens a
|
|
89
|
+
pop-up window instead; when the pop-up finishes, it closes and the framed page
|
|
90
|
+
reloads signed in. If the browser blocks the pop-up the page says so.
|
|
91
|
+
|
|
92
|
+
Each attempt is bound to the browser that started it by a sealed ten-minute
|
|
93
|
+
cookie and checked with PKCE, `state`, `nonce` and the issuer's `iss`; a stale
|
|
94
|
+
or foreign attempt reads "This sign-in took too long or started in another
|
|
95
|
+
browser. Start again."
|
|
96
|
+
|
|
97
|
+
The first sign-in creates the `users` row (`auth_provider` `oidc`,
|
|
98
|
+
`auth_provider_user_sid` the issuer's subject) with the email and name.
|
|
99
|
+
Apps trust that email (invitations match it), so when the issuer says
|
|
100
|
+
`email_verified: false` the sign-in stops with "Your account provider has not
|
|
101
|
+
confirmed your email address yet." An accounts hub never sends an unconfirmed
|
|
102
|
+
email; it asks the person to confirm first.
|
|
103
|
+
|
|
104
|
+
## Signing out
|
|
105
|
+
|
|
106
|
+
- Ordinary sign-out ends the app session only.
|
|
107
|
+
- `/api/auth/oidc/logout?everywhere=1` (a same-site link) also ends the issuer
|
|
108
|
+
session and returns to `/`.
|
|
109
|
+
- The issuer can end app sessions itself: disabling an account in the hub posts
|
|
110
|
+
a signed logout token to the back-channel URI, and the person's sessions in
|
|
111
|
+
this app end at once.
|
|
112
|
+
|
|
113
|
+
## Preview identity
|
|
114
|
+
|
|
115
|
+
Keep the standard managed-preview login (`tools/preview-identity`, see
|
|
116
|
+
[Authentication](/guide/app-setup/authentication)). It signs the Preview in as
|
|
117
|
+
an existing `users` row without visiting the issuer, so tests do not need a
|
|
118
|
+
hub account. It cannot create users.
|
|
119
|
+
|
|
120
|
+
## Move existing local accounts
|
|
121
|
+
|
|
122
|
+
Only with the app owner's explicit yes. On the app (local provider still
|
|
123
|
+
installed):
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
npx jskit-oidc-sign-in export-local-accounts --out accounts.jsonl
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
This writes one JSON line per account, readable only by you, and refuses to
|
|
130
|
+
overwrite a file. Import that file into the hub (`jskit-oidc-issuer
|
|
131
|
+
import-accounts`, see the hub guide). Then switch the provider as above and
|
|
132
|
+
mark the same people as hub accounts:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
npx jskit-oidc-sign-in adopt-oidc --issuer "$AUTH_OIDC_ISSUER" --in accounts.jsonl
|
|
136
|
+
npx jskit-oidc-sign-in adopt-oidc --issuer "$AUTH_OIDC_ISSUER" --in accounts.jsonl --apply
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The first run only counts what would change; `--apply` changes it. Ids stay the
|
|
140
|
+
same, so existing data keeps its owners. Delete `accounts.jsonl` afterwards: it
|
|
141
|
+
contains password hashes.
|
|
142
|
+
|
|
143
|
+
## Verification
|
|
144
|
+
|
|
145
|
+
- Sign in unframed and in the Preview; refresh stays signed in.
|
|
146
|
+
- Sign out, then sign out everywhere.
|
|
147
|
+
- Disable the account in the hub and confirm the app session ends.
|
|
148
|
+
- Preview identity still signs in.
|
|
@@ -189,6 +189,19 @@ Commit `package.json`, every changed workspace manifest, and
|
|
|
189
189
|
updater succeeds; select a different published cohort only through a catalog
|
|
190
190
|
that advertises it.
|
|
191
191
|
|
|
192
|
+
## Host-only production cookies
|
|
193
|
+
|
|
194
|
+
In production (`NODE_ENV=production`, served over HTTPS) the session cookies of
|
|
195
|
+
the local, Supabase and OIDC auth providers and the CSRF secret cookie use the
|
|
196
|
+
`__Host-` prefix, for example `__Host-jskit_local_access_token` and
|
|
197
|
+
`__Host-_csrf`. Browsers accept these only with `Secure`, `Path=/` and no
|
|
198
|
+
`Domain`, so a sibling subdomain cannot plant or overwrite them. The first
|
|
199
|
+
production deploy after updating signs everyone out once. Development and tests
|
|
200
|
+
keep the unprefixed names.
|
|
201
|
+
Setting `AUTH_CSRF_COOKIE_SECURE=false` keeps the unprefixed CSRF cookie for an
|
|
202
|
+
application deliberately served over plain HTTP. CSRF protection is still the
|
|
203
|
+
token check on every unsafe request; the prefix only hardens the cookie.
|
|
204
|
+
|
|
192
205
|
## Read cancellation and deadlines
|
|
193
206
|
|
|
194
207
|
The standard endpoint, list, view, form-read, and CRUD read composables pass
|
|
@@ -90,6 +90,9 @@ the npm installation.
|
|
|
90
90
|
|
|
91
91
|
Do not add auth, users, workspaces, console, sample data, databases, or AI
|
|
92
92
|
capabilities unless the product choice requires them.
|
|
93
|
+
When accounts are required, `auth/auth-surface` includes the managed-preview
|
|
94
|
+
login as standard: add `tools/preview-identity` and its `#### Preview identity`
|
|
95
|
+
Outputs block together with the rest of the surface.
|
|
93
96
|
|
|
94
97
|
## Author database-backed CRUD
|
|
95
98
|
|
|
@@ -55,6 +55,17 @@ shared-screen controls; avoid duplicates, drawer-only access, or adding a page
|
|
|
55
55
|
heading just to house it. Keep its meaning and accessible name clear at every
|
|
56
56
|
supported width.
|
|
57
57
|
|
|
58
|
+
### Scroll position
|
|
59
|
+
|
|
60
|
+
`createShellRouter()` from `@jskit-ai/kernel/client` installs
|
|
61
|
+
`shellScrollBehavior` by default: a new screen opens at the top (or at its
|
|
62
|
+
hash target), Back/Forward restore the saved position, and query, hash, tab or
|
|
63
|
+
sub-view changes within the same page keep the current position. A tab or
|
|
64
|
+
sub-view counts as the same page when both locations share a parent page record
|
|
65
|
+
below the surface root. Pass `scrollBehavior` to `createShellRouter()` to
|
|
66
|
+
replace it with your own Vue Router function, or `scrollBehavior: false` to
|
|
67
|
+
disable it. Do not wrap the router or reset scroll in page components.
|
|
68
|
+
|
|
58
69
|
## Application-owned files
|
|
59
70
|
|
|
60
71
|
Pattern source is ordinary customizable application source. When replacing a
|
|
@@ -93,6 +104,19 @@ icon/label and label/end gaps. The normal 80px rail centres 48px targets;
|
|
|
93
104
|
`railWidth` and `drawerWidth` are public density/width controls. Do not override
|
|
94
105
|
the shell's private implementation CSS.
|
|
95
106
|
|
|
107
|
+
The app bar, drawer/rail and compact bottom navigation follow the Vuetify theme
|
|
108
|
+
and expose restyling tokens instead of hard-coded chrome: `--shell-chrome-border-width`
|
|
109
|
+
and `--shell-chrome-border-color` for the shared dividers,
|
|
110
|
+
`--shell-app-bar-border-width`, `--shell-navigation-border-width` and
|
|
111
|
+
`--shell-bottom-navigation-border-width` per edge, and
|
|
112
|
+
`--shell-app-bar-background`, `--shell-navigation-background` and
|
|
113
|
+
`--shell-bottom-navigation-background` for the surfaces. The defaults keep one
|
|
114
|
+
thin divider on each separating edge, because Vuetify's default themes define
|
|
115
|
+
no Material 3 surface-container roles to separate surfaces tonally. A Material 3
|
|
116
|
+
restyle sets the border widths to `0` and gives navigation a tonal surface, for
|
|
117
|
+
example `--shell-navigation-background: rgb(var(--v-theme-surface-container-low))`
|
|
118
|
+
when the theme defines that role.
|
|
119
|
+
|
|
96
120
|
## Browser verification
|
|
97
121
|
|
|
98
122
|
Exercise user-facing changes with Playwright at compact, medium, and expanded
|
package/guide/agent/index.md
CHANGED
|
@@ -14,6 +14,8 @@ apply or adapt. It does not prescribe an agent host or project orchestrator.
|
|
|
14
14
|
- [Migrate an existing application](/guide/app-setup/existing-application-migration)
|
|
15
15
|
- [A more interesting shell](/guide/app-setup/a-more-interesting-shell)
|
|
16
16
|
- [Authentication](/guide/app-setup/authentication)
|
|
17
|
+
- [Sign in through an OIDC issuer](/guide/app-setup/sign-in-through-oidc-issuer)
|
|
18
|
+
- [Run an accounts hub](/guide/app-setup/run-an-accounts-hub)
|
|
17
19
|
- [Database layer](/guide/app-setup/database-layer)
|
|
18
20
|
- [Users](/guide/app-setup/users)
|
|
19
21
|
- [Multi-homing](/guide/app-setup/multi-homing)
|
package/package.json
CHANGED
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@local/main": "0.1.0",
|
|
36
36
|
"@fastify/static": "^10.1.3",
|
|
37
|
-
"@jskit-ai/kernel": "0.1.
|
|
37
|
+
"@jskit-ai/kernel": "0.1.245",
|
|
38
38
|
"@tanstack/vue-query": "^5.101.0",
|
|
39
39
|
"fastify": "^5.8.5",
|
|
40
40
|
"json-rest-schema": "^1.0.17",
|
|
@@ -42,13 +42,13 @@
|
|
|
42
42
|
"vue": "^3.5.44",
|
|
43
43
|
"vue-router": "^5.3.1",
|
|
44
44
|
"vuetify": "^4.1.2",
|
|
45
|
-
"@jskit-ai/http-runtime": "0.1.
|
|
45
|
+
"@jskit-ai/http-runtime": "0.1.243",
|
|
46
46
|
"@fastify/fast-json-stringify-compiler": "^5.1.0",
|
|
47
47
|
"@vue/devtools-api": "^8.2.1"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@jskit-ai/config-eslint": "0.1.241",
|
|
51
|
-
"@jskit-ai/jskit-catalog": "0.1.
|
|
51
|
+
"@jskit-ai/jskit-catalog": "0.1.294",
|
|
52
52
|
"@playwright/test": "1.61.1",
|
|
53
53
|
"@vitejs/plugin-vue": "^6.0.7",
|
|
54
54
|
"eslint": "^10.8.0",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@local/main": "0.1.0",
|
|
36
36
|
"@fastify/static": "^10.1.3",
|
|
37
|
-
"@jskit-ai/kernel": "0.1.
|
|
37
|
+
"@jskit-ai/kernel": "0.1.245",
|
|
38
38
|
"@tanstack/vue-query": "^5.101.0",
|
|
39
39
|
"fastify": "^5.8.5",
|
|
40
40
|
"json-rest-schema": "^1.0.17",
|
|
@@ -42,15 +42,15 @@
|
|
|
42
42
|
"vue": "^3.5.44",
|
|
43
43
|
"vue-router": "^5.3.1",
|
|
44
44
|
"vuetify": "^4.1.2",
|
|
45
|
-
"@jskit-ai/http-runtime": "0.1.
|
|
45
|
+
"@jskit-ai/http-runtime": "0.1.243",
|
|
46
46
|
"@mdi/js": "^7.4.47",
|
|
47
|
-
"@jskit-ai/shell-web": "0.1.
|
|
47
|
+
"@jskit-ai/shell-web": "0.1.250",
|
|
48
48
|
"@fastify/fast-json-stringify-compiler": "^5.1.0",
|
|
49
49
|
"@vue/devtools-api": "^8.2.1"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@jskit-ai/config-eslint": "0.1.241",
|
|
53
|
-
"@jskit-ai/jskit-catalog": "0.1.
|
|
53
|
+
"@jskit-ai/jskit-catalog": "0.1.294",
|
|
54
54
|
"@playwright/test": "1.61.1",
|
|
55
55
|
"@vitejs/plugin-vue": "^6.0.7",
|
|
56
56
|
"eslint": "^10.8.0",
|
|
@@ -141,6 +141,7 @@ Exports
|
|
|
141
141
|
- `resolveAllowedOriginsFromSurfaceDefinitions(surfaceDefinitions = {}, { seedOrigins = [] } = {})`
|
|
142
142
|
- `resolveAllowedOriginsFromPlacementContext(contextValue = null, { includeWindowOrigin = true } = {})`
|
|
143
143
|
Local functions
|
|
144
|
+
- `staysOnSameOrigin(path)`
|
|
144
145
|
- `appendNormalizedOrigin(origins, value)`
|
|
145
146
|
- `normalizeBlockedPathnames(blockedPathnames = [])`
|
|
146
147
|
|