@zitadel/cli 0.3.0 → 0.4.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/README.md +39 -0
- package/dist/index.mjs +1450 -1047
- package/dist/index.mjs.map +1 -1
- package/dist/lib/oclif/help.mjs +3 -2
- package/dist/lib/oclif/help.mjs.map +1 -1
- package/dist/skills/zitadel/SKILL.md +111 -0
- package/dist/skills/zitadel-cli/SKILL.md +635 -0
- package/dist/skills/zitadel-cli/references/driving-login-ui.md +124 -0
- package/dist/skills/zitadel-components/SKILL.md +152 -0
- package/dist/skills/zitadel-sdk-angular/SKILL.md +149 -0
- package/dist/skills/zitadel-sdk-next/SKILL.md +174 -0
- package/dist/skills/zitadel-sdk-nuxt/SKILL.md +149 -0
- package/dist/skills/zitadel-sdk-qwik/SKILL.md +136 -0
- package/dist/skills/zitadel-sdk-qwik-router/SKILL.md +126 -0
- package/dist/skills/zitadel-sdk-react/SKILL.md +149 -0
- package/dist/skills/zitadel-sdk-solid/SKILL.md +144 -0
- package/dist/skills/zitadel-sdk-solid-start/SKILL.md +149 -0
- package/dist/skills/zitadel-sdk-svelte/SKILL.md +137 -0
- package/dist/skills/zitadel-sdk-sveltekit/SKILL.md +147 -0
- package/dist/skills/zitadel-sdk-tanstack-start/SKILL.md +150 -0
- package/dist/skills/zitadel-sdk-vue/SKILL.md +147 -0
- package/dist/{skills-hint-N1H5-ny1.mjs → skills-hint-C8oe8cCo.mjs} +1446 -231
- package/dist/skills-hint-C8oe8cCo.mjs.map +1 -0
- package/oclif.manifest.json +102 -3
- package/package.json +8 -5
- package/skills/zitadel-cli/SKILL.md +62 -9
- package/dist/skills-hint-N1H5-ny1.mjs.map +0 -1
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: zitadel-sdk-solid
|
|
3
|
+
description: >-
|
|
4
|
+
Integrate Zitadel authentication into a SolidJS app with
|
|
5
|
+
`@zitadel/sdk-solid`. Use when the user wants to add Zitadel login,
|
|
6
|
+
registration, logout, or a signed-in session card to an existing or
|
|
7
|
+
custom Solid SPA (Vite, SolidStart, etc.) — wiring `configureZitadel`
|
|
8
|
+
and the `<ZitadelLogin>` / `<ZitadelLogout>` / `<ZitadelSession>`
|
|
9
|
+
components by hand rather than scaffolding from scratch.
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# @zitadel/sdk-solid
|
|
13
|
+
|
|
14
|
+
Solid components that render the Zitadel auth UI inside a client-side SPA.
|
|
15
|
+
The package wraps the framework-agnostic `<zitadel-*>` web components as
|
|
16
|
+
real Solid components, so login, logout, and the signed-in session card are
|
|
17
|
+
JSX you drop into your routes.
|
|
18
|
+
|
|
19
|
+
## When to use
|
|
20
|
+
|
|
21
|
+
- **Fresh project:** prefer the CLI. `npx @zitadel/cli@latest setup --framework solid`
|
|
22
|
+
scaffolds a wired Solid app (and the dev proxy) for you — see the
|
|
23
|
+
`zitadel-cli` skill. Don't hand-assemble what the CLI generates.
|
|
24
|
+
- **This skill:** an app that already exists, or a custom integration the
|
|
25
|
+
scaffold doesn't cover — adding auth to a Solid app you already have,
|
|
26
|
+
moving the components into your own routes, or wiring the config yourself.
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
`solid-js >= 1.6` is a peer dependency, and the published types need
|
|
31
|
+
TypeScript >= 5.0.
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
npm install @zitadel/sdk-solid@latest
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Integrate
|
|
38
|
+
|
|
39
|
+
Configure once, then render the components. `configureZitadel` returns a
|
|
40
|
+
project handle you pass to each component.
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
import { ZitadelLogin, configureZitadel } from '@zitadel/sdk-solid';
|
|
44
|
+
|
|
45
|
+
const project = configureZitadel({
|
|
46
|
+
projectId: import.meta.env.VITE_ZITADEL_PROJECT_ID,
|
|
47
|
+
proxyPath: '/__nextgen',
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
export default function LoginPage() {
|
|
51
|
+
return <ZitadelLogin project={project} purpose="login" postSignInUrl="/" />;
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Logout and the signed-in session card take the same `project` handle:
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
import { ZitadelLogout, ZitadelSession } from '@zitadel/sdk-solid';
|
|
59
|
+
|
|
60
|
+
<ZitadelLogout project={project} postSignOutUrl="/login" />;
|
|
61
|
+
<ZitadelSession project={project} />;
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`purpose` selects the flow (`"login"`, etc.); `postSignInUrl` /
|
|
65
|
+
`postSignOutUrl` are where the widget navigates after the flow completes.
|
|
66
|
+
The widget's events reach you as the callbacks listed under Widget props and
|
|
67
|
+
events.
|
|
68
|
+
|
|
69
|
+
**Same-origin proxy.** The widgets call `${proxyPath}/…` same-origin
|
|
70
|
+
(default `/__nextgen`). For local development the CLI dev proxy covers this;
|
|
71
|
+
you can also skip the proxy and point `proxyPath` straight at the backend
|
|
72
|
+
cross-origin, e.g. `proxyPath: "http://localhost:8080"` (the `zitadel start`
|
|
73
|
+
local runtime default port).
|
|
74
|
+
|
|
75
|
+
## Widget props and events
|
|
76
|
+
|
|
77
|
+
`ZitadelLogin`, `ZitadelLogout` and `ZitadelSession` take the props below, spelled the same in every SPA SDK. An unset prop keeps the widget's own default.
|
|
78
|
+
|
|
79
|
+
| Prop | Type | Default | Widgets | Description |
|
|
80
|
+
| --- | --- | --- | --- | --- |
|
|
81
|
+
| `project` | `ZitadelProject` | unset | Login, Logout, Session | The handle from `configureZitadel(...)`. Wins over `projectId` and `proxyPath`. |
|
|
82
|
+
| `projectId` | `string` | unset | Login, Logout, Session | Project id, read when no `project` handle is passed. |
|
|
83
|
+
| `proxyPath` | `string` | `"/__nextgen"` | Login, Logout, Session | Same-origin path the widget calls. |
|
|
84
|
+
| `purpose` | `CreateFlowBodyPurpose` | `"login"` | Login | Flow purpose. |
|
|
85
|
+
| `flowName` | `string` | unset | Login | Runs the flow definition with this `name`; unset runs the project's default flow for the purpose. |
|
|
86
|
+
| `postSignInUrl` | `string` | unset | Login | Where to navigate after a completed sign-in. When the page's `next` query parameter names a path on the same origin, as the server SDKs' middleware sets it for a signed-out visit to a protected route, the widget returns there instead. |
|
|
87
|
+
| `forcePostSignInUrl` | `boolean` | `false` | Login | Navigates to `postSignInUrl` even when the page's `next` query parameter names a path, for a page that uses `next` for something of its own. |
|
|
88
|
+
| `postSignOutUrl` | `string` | unset | Logout, Session | Where to navigate after sign-out. |
|
|
89
|
+
| `resumeFlowId` | `string` or `null` | unset | Login | An existing flow's id to resume instead of starting a new flow; unset, `null` or `""` falls back to the `flow` query parameter, and an id that no longer resolves starts a new flow. |
|
|
90
|
+
| `variant` | `"widget"` or `"page"` | `"widget"` | Login, Session | `widget` is content-sized and paints no page chrome; `page` claims the viewport, paints the surface background and loads the brand font, and on Login focuses the first field. |
|
|
91
|
+
| `theme` | `"light"`, `"dark"` or `"auto"` | unset | Login, Logout, Session | Colour mode. Unset follows the tenant's branding theme on Login, then the variant default (`dark` for `page`, `auto` for `widget`); Logout defaults to `auto`. `auto` follows `prefers-color-scheme`. |
|
|
92
|
+
| `suppressHeader` | `boolean` | `false` | Login, Session | Visually hides the widget's own heading block while keeping it in the accessibility tree, for pages that already carry the heading. |
|
|
93
|
+
| `suppressPasswordToggle` | `boolean` | `false` | Login | Hides the show/hide button on password fields. |
|
|
94
|
+
| `heading` | `string` | `"Signed in as"` | Session | Heading text override. |
|
|
95
|
+
| `logoutLabel` | `string` | `"Sign out"` | Session | Logout action label override. |
|
|
96
|
+
| `locales` | `Record<string, Partial<Record<string, string>>>` | unset | Login | Copy overrides merged over the builtin dictionaries, keyed by primary language subtag, for example `{ en: { "identifier.title": "Welcome back" } }`. |
|
|
97
|
+
| `lang` | `string` | browser language | Login | BCP-47 language override. |
|
|
98
|
+
|
|
99
|
+
Each widget event reaches the callback in the last column, which receives the event's `detail` payload.
|
|
100
|
+
|
|
101
|
+
| Widget event | Fires when | Detail | Widgets | Callback |
|
|
102
|
+
| --- | --- | --- | --- | --- |
|
|
103
|
+
| `zitadel-flow-step` | Login shows a step, the first one included. | `{ step }` | Login | `onFlowStep` |
|
|
104
|
+
| `zitadel-flow-input` | The visitor edits a field. | `{ name, value }` | Login | `onFlowInput` |
|
|
105
|
+
| `zitadel-flow-complete` | The flow reaches a terminal step. | `{ behavior, redirect_uri?, handoff_token?, handoff_token_expires_at? }` | Login | `onFlowComplete` |
|
|
106
|
+
| `zitadel-flow-redirect` | The widget hands the browser to an identity provider; nobody is signed in yet. | `{ redirect_url, step }` | Login | `onFlowRedirect` |
|
|
107
|
+
| `zitadel-flow-error` | The flow reports an error. | `{ message }` | Login | `onFlowError` |
|
|
108
|
+
| `zitadel-signout` | The user signs out. | `{ display, identifier }` | Logout, Session | `onSignout` |
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
<ZitadelLogin project={project} theme="light" onFlowComplete={(detail) => track(detail)} />
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
When your callback for `zitadel-flow-complete`, `zitadel-flow-redirect` or `zitadel-signout` returns a promise, the widget waits for it to settle (up to two seconds) before it navigates.
|
|
115
|
+
|
|
116
|
+
## Read these, don't guess
|
|
117
|
+
|
|
118
|
+
Treat the installed package as authoritative over anything here — this skill
|
|
119
|
+
and the package version move independently.
|
|
120
|
+
|
|
121
|
+
- `node_modules/@zitadel/sdk-solid/README.md` — the shipped usage doc.
|
|
122
|
+
- `node_modules/@zitadel/sdk-solid/dist/index.d.ts` and the re-exported
|
|
123
|
+
`@zitadel/sdk-core/types` — the real prop names, component props
|
|
124
|
+
(`ZitadelLoginProps`, `ZitadelLogoutProps`, `ZitadelSessionProps`), and
|
|
125
|
+
`configureZitadel`'s config shape. Read the types before wiring a prop you
|
|
126
|
+
are unsure of rather than assuming its name.
|
|
127
|
+
|
|
128
|
+
Exported surface (discover-first, confirm against the types above):
|
|
129
|
+
`configureZitadel`, `getApi`, `getZitadelConfig`, the `ZitadelLogin` /
|
|
130
|
+
`ZitadelLogout` / `ZitadelSession` components, `businessLocales`, and the
|
|
131
|
+
`ZitadelConfig` / `ZitadelProject` types.
|
|
132
|
+
|
|
133
|
+
## Gotchas
|
|
134
|
+
|
|
135
|
+
- **Server rendering.** If your app renders on the server, mount the widget on the client only, after hydration, or pass `projectId` and `proxyPath` to the `ZitadelLogin` wrapper as strings (it writes them as the `project-id` and `proxy-path` attributes; use those hyphenated names only on a raw `<zitadel-login>` element), because a widget that starts before its configuration arrives shows an error instead of the flow.
|
|
136
|
+
- **Production SPA deployment is not yet supported.** The same-origin proxy
|
|
137
|
+
path must come from your hosting platform, and the CLI can't scaffold those
|
|
138
|
+
configs yet, so a production SPA build has no proxy to talk to. See
|
|
139
|
+
ADR 036 and zitadel/nextgen#560. The CLI dev proxy covers local
|
|
140
|
+
development only.
|
|
141
|
+
- **TypeScript < 5.0 won't type-check.** The published `.d.ts` re-exports
|
|
142
|
+
with `export type *`, introduced in TS 5.0.
|
|
143
|
+
- **`solid-js` is a peer dependency** (`>= 1.6`) — install it in the host
|
|
144
|
+
app; the package does not bundle it.
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: zitadel-sdk-solid-start
|
|
3
|
+
description: >-
|
|
4
|
+
Integrate Zitadel authentication into an existing or custom SolidStart app
|
|
5
|
+
with @zitadel/sdk-solid-start. Use when the user wants login, logout, session
|
|
6
|
+
handling, or protected routes in a SolidStart 2 app and is wiring the SDK by
|
|
7
|
+
hand rather than letting the CLI scaffold a fresh project — registering the
|
|
8
|
+
middleware, reading auth state in a server function, or rendering the
|
|
9
|
+
`ZitadelLogin` / `ZitadelSession` widgets.
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# @zitadel/sdk-solid-start
|
|
13
|
+
|
|
14
|
+
SolidStart middleware and helpers that add Zitadel (Nextgen) auth to a
|
|
15
|
+
SolidStart app. The middleware proxies auth traffic same-origin under
|
|
16
|
+
`/__nextgen`, verifies the session JWT via JWKS on the server, writes the result
|
|
17
|
+
to `event.locals.nextgenAuth`, and redirects unauthenticated requests on
|
|
18
|
+
protected routes. The package is server-only; the widgets come from
|
|
19
|
+
`@zitadel/sdk-solid`.
|
|
20
|
+
|
|
21
|
+
## When to use
|
|
22
|
+
|
|
23
|
+
The `zitadel` CLI (`zitadel setup --framework solid-start`) scaffolds the
|
|
24
|
+
middleware, its `vite.config.ts` registration, login/register/profile routes,
|
|
25
|
+
and `.env.local` into a fresh or detected SolidStart project — prefer it for
|
|
26
|
+
greenfield work. It refuses a SolidStart 1 app. Reach for **this skill** when you
|
|
27
|
+
are adding auth to an **existing or custom** SolidStart app by hand, or
|
|
28
|
+
adjusting a scaffolded wiring.
|
|
29
|
+
|
|
30
|
+
## Install
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pnpm add @zitadel/sdk-solid-start@latest
|
|
34
|
+
# the login/logout/session widgets are a separate package:
|
|
35
|
+
pnpm add @zitadel/sdk-solid@latest
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Peer deps: `@solidjs/start ^2.0.0`, `solid-js ^1.8.0`.
|
|
39
|
+
|
|
40
|
+
## Integrate
|
|
41
|
+
|
|
42
|
+
**1. Middleware.** Create `src/middleware.ts`, wrapped in SolidStart's
|
|
43
|
+
`createMiddleware`, and register it with the `solidStart()` Vite plugin:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
// src/middleware.ts
|
|
47
|
+
import { createMiddleware } from '@solidjs/start/middleware';
|
|
48
|
+
import { createNextgenMiddleware } from '@zitadel/sdk-solid-start/server';
|
|
49
|
+
|
|
50
|
+
export default createMiddleware(
|
|
51
|
+
createNextgenMiddleware({
|
|
52
|
+
protectedRoutes: ['/admin', '/dashboard*'], // trailing * matches sub-paths
|
|
53
|
+
loginPath: '/login',
|
|
54
|
+
}),
|
|
55
|
+
);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
// vite.config.ts
|
|
60
|
+
import { defineConfig } from 'vite';
|
|
61
|
+
import { solidStart } from '@solidjs/start/config';
|
|
62
|
+
import { nitro } from 'nitro/vite';
|
|
63
|
+
|
|
64
|
+
export default defineConfig({
|
|
65
|
+
plugins: [solidStart({ middleware: './src/middleware.ts' }), nitro()],
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`url` and `projectSecret` default to `ZITADEL_URL` and `ZITADEL_PROJECT_SECRET`
|
|
70
|
+
from the server environment; pass them only to override. Sessions count only in
|
|
71
|
+
the app's own project: `projectId`, else `ZITADEL_PROJECT_ID`, else
|
|
72
|
+
`VITE_ZITADEL_PROJECT_ID`. With none set, nobody is signed in. To compose with your own
|
|
73
|
+
handlers, spread the config's `onRequest` into your own `createMiddleware` call.
|
|
74
|
+
|
|
75
|
+
**2. Read auth server-side** with `getAuth(getRequestEvent()!)` inside a
|
|
76
|
+
`'use server'` function:
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import { getRequestEvent } from 'solid-js/web';
|
|
80
|
+
import { getAuth } from '@zitadel/sdk-solid-start/server';
|
|
81
|
+
|
|
82
|
+
export function requireUser() {
|
|
83
|
+
'use server';
|
|
84
|
+
const auth = getAuth(getRequestEvent()!);
|
|
85
|
+
if (!auth.isAuthenticated) throw new Error('Unauthorized');
|
|
86
|
+
return auth.session.userId;
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
`protectedRoutes` only guards full page loads. To keep a route from rendering at
|
|
91
|
+
all without a session, check the session in a `query` that `throw redirect('/login')`
|
|
92
|
+
and call it from the route's `preload` — it runs on the server for client-side
|
|
93
|
+
navigation too.
|
|
94
|
+
|
|
95
|
+
**3. Render the widgets** from `@zitadel/sdk-solid`, loaded with SolidStart's
|
|
96
|
+
`clientOnly` so they are created in the browser and the package stays out of the
|
|
97
|
+
server render:
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
import { clientOnly } from '@solidjs/start';
|
|
101
|
+
|
|
102
|
+
const ZitadelLogin = clientOnly(() =>
|
|
103
|
+
import('@zitadel/sdk-solid').then((m) => ({ default: m.ZitadelLogin })),
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
export default function Login() {
|
|
107
|
+
return (
|
|
108
|
+
<ZitadelLogin
|
|
109
|
+
projectId={import.meta.env.VITE_ZITADEL_PROJECT_ID}
|
|
110
|
+
proxyPath="/__nextgen"
|
|
111
|
+
purpose="login"
|
|
112
|
+
postSignInUrl="/admin"
|
|
113
|
+
/>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
`ZitadelSession` (with `postSignOutUrl="/login"`) and `ZitadelLogout` load the
|
|
119
|
+
same way.
|
|
120
|
+
|
|
121
|
+
## Widget props and events
|
|
122
|
+
|
|
123
|
+
This SDK is server-only. The widgets come from `@zitadel/sdk-solid`, so read its skill for the widget props and events.
|
|
124
|
+
|
|
125
|
+
## Read these, don't guess
|
|
126
|
+
|
|
127
|
+
The package README at `node_modules/@zitadel/sdk-solid-start/README.md` and the
|
|
128
|
+
bundled `.d.ts` types (`dist/server.d.ts`, `dist/client.d.ts`) are authoritative
|
|
129
|
+
and versioned with the installed package — read them before wiring anything, and
|
|
130
|
+
let them override anything remembered. This skill teaches the pattern, not a
|
|
131
|
+
full catalog of options or the shared JWT-verification pipeline (that lives in
|
|
132
|
+
`@zitadel/sdk-core`). For widget props and callbacks, read
|
|
133
|
+
`node_modules/@zitadel/sdk-solid/README.md` and its types. Check exact option
|
|
134
|
+
names and defaults against the installed version rather than assuming.
|
|
135
|
+
|
|
136
|
+
## Gotchas
|
|
137
|
+
|
|
138
|
+
- **Wrap the config in `createMiddleware`.** SolidStart 2 registers the default
|
|
139
|
+
export as an array of h3 middleware; exporting the bare
|
|
140
|
+
`createNextgenMiddleware(...)` object registers nothing and `/__nextgen/*`
|
|
141
|
+
404s.
|
|
142
|
+
- **Pass `projectId` / `proxyPath` as props, not a `configureZitadel` handle.**
|
|
143
|
+
Building the handle imports `@zitadel/sdk-solid` at module scope, outside the
|
|
144
|
+
`clientOnly` boundary.
|
|
145
|
+
- **`@zitadel/sdk-solid-start` renders no widgets.** They come from
|
|
146
|
+
`@zitadel/sdk-solid`, which registers custom elements on import — never import
|
|
147
|
+
it at module scope in a server-rendered file.
|
|
148
|
+
- **Client-side navigation skips the middleware.** Without a preloaded server
|
|
149
|
+
query, only the `ZitadelSession` card sends a signed-out visitor away.
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: zitadel-sdk-svelte
|
|
3
|
+
description: >-
|
|
4
|
+
Integrate Zitadel authentication into an existing Svelte or SvelteKit app
|
|
5
|
+
with the @zitadel/sdk-svelte components. Use when the user wants to add login,
|
|
6
|
+
logout, or a signed-in session card to a Svelte 5 / SvelteKit (or Vite SPA)
|
|
7
|
+
project by hand, wire the auth widgets to a backend, or debug the proxy and
|
|
8
|
+
post sign-in/out redirects.
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# @zitadel/sdk-svelte
|
|
12
|
+
|
|
13
|
+
`@zitadel/sdk-svelte` ships Svelte 5 components that render the Zitadel auth UI
|
|
14
|
+
(`<ZitadelLogin>`, `<ZitadelLogout>`, `<ZitadelSession>`) for client-side SPAs.
|
|
15
|
+
The components wrap the `@zitadel/components` custom elements and talk to a
|
|
16
|
+
Zitadel backend over a same-origin proxy path.
|
|
17
|
+
|
|
18
|
+
## When to use
|
|
19
|
+
|
|
20
|
+
Use this skill for an **existing or custom** Svelte / SvelteKit / Vite app where
|
|
21
|
+
you are adding the auth widgets by hand.
|
|
22
|
+
|
|
23
|
+
If the user is starting fresh, prefer the `zitadel` CLI instead — it scaffolds a
|
|
24
|
+
working Svelte app and wires the dev proxy for you:
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
npx @zitadel/cli@latest setup --framework svelte --non-interactive --json
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Install
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
npm install @zitadel/sdk-svelte@latest
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Peer dependencies: `svelte ^5.0.0`. Requires TypeScript ≥ 5.0 (the published types use `export type *`).
|
|
37
|
+
|
|
38
|
+
## Integrate
|
|
39
|
+
|
|
40
|
+
The widgets are **browser** components. In SvelteKit, mount them in a
|
|
41
|
+
`+page.svelte` (they render client-side). The minimal pattern, from the README:
|
|
42
|
+
|
|
43
|
+
```svelte
|
|
44
|
+
<script lang="ts">
|
|
45
|
+
import { ZitadelLogin, ZitadelLogout, configureZitadel } from '@zitadel/sdk-svelte';
|
|
46
|
+
|
|
47
|
+
const project = configureZitadel({
|
|
48
|
+
projectId: import.meta.env.VITE_ZITADEL_PROJECT_ID,
|
|
49
|
+
proxyPath: '/__nextgen',
|
|
50
|
+
});
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<ZitadelLogin {project} purpose="login" postSignInUrl="/" />
|
|
54
|
+
<ZitadelLogout {project} postSignOutUrl="/login" />
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
- **Configure once** with `configureZitadel({ projectId, proxyPath })` and pass
|
|
58
|
+
the returned `project` to each component.
|
|
59
|
+
- **Proxy / same-origin.** The widgets call `${proxyPath}/…` same-origin
|
|
60
|
+
(default `/__nextgen`). For local development you can skip the proxy and point
|
|
61
|
+
`proxyPath` straight at the backend (cross-origin), e.g.
|
|
62
|
+
`proxyPath: "http://localhost:8080"` (the `zitadel start` default port).
|
|
63
|
+
- **Post URLs.** `postSignInUrl` (on `ZitadelLogin`) and `postSignOutUrl` (on
|
|
64
|
+
`ZitadelLogout`) are where the browser lands after each flow.
|
|
65
|
+
- **Session card.** `<ZitadelSession {project} />` renders the signed-in user.
|
|
66
|
+
- **Callbacks** are optional props; see Widget props and events.
|
|
67
|
+
|
|
68
|
+
## Widget props and events
|
|
69
|
+
|
|
70
|
+
`ZitadelLogin`, `ZitadelLogout` and `ZitadelSession` take the props below, spelled the same in every SPA SDK. An unset prop keeps the widget's own default.
|
|
71
|
+
|
|
72
|
+
| Prop | Type | Default | Widgets | Description |
|
|
73
|
+
| --- | --- | --- | --- | --- |
|
|
74
|
+
| `project` | `ZitadelProject` | unset | Login, Logout, Session | The handle from `configureZitadel(...)`. Wins over `projectId` and `proxyPath`. |
|
|
75
|
+
| `projectId` | `string` | unset | Login, Logout, Session | Project id, read when no `project` handle is passed. |
|
|
76
|
+
| `proxyPath` | `string` | `"/__nextgen"` | Login, Logout, Session | Same-origin path the widget calls. |
|
|
77
|
+
| `purpose` | `CreateFlowBodyPurpose` | `"login"` | Login | Flow purpose. |
|
|
78
|
+
| `flowName` | `string` | unset | Login | Runs the flow definition with this `name`; unset runs the project's default flow for the purpose. |
|
|
79
|
+
| `postSignInUrl` | `string` | unset | Login | Where to navigate after a completed sign-in. When the page's `next` query parameter names a path on the same origin, as the server SDKs' middleware sets it for a signed-out visit to a protected route, the widget returns there instead. |
|
|
80
|
+
| `forcePostSignInUrl` | `boolean` | `false` | Login | Navigates to `postSignInUrl` even when the page's `next` query parameter names a path, for a page that uses `next` for something of its own. |
|
|
81
|
+
| `postSignOutUrl` | `string` | unset | Logout, Session | Where to navigate after sign-out. |
|
|
82
|
+
| `resumeFlowId` | `string` or `null` | unset | Login | An existing flow's id to resume instead of starting a new flow; unset, `null` or `""` falls back to the `flow` query parameter, and an id that no longer resolves starts a new flow. |
|
|
83
|
+
| `variant` | `"widget"` or `"page"` | `"widget"` | Login, Session | `widget` is content-sized and paints no page chrome; `page` claims the viewport, paints the surface background and loads the brand font, and on Login focuses the first field. |
|
|
84
|
+
| `theme` | `"light"`, `"dark"` or `"auto"` | unset | Login, Logout, Session | Colour mode. Unset follows the tenant's branding theme on Login, then the variant default (`dark` for `page`, `auto` for `widget`); Logout defaults to `auto`. `auto` follows `prefers-color-scheme`. |
|
|
85
|
+
| `suppressHeader` | `boolean` | `false` | Login, Session | Visually hides the widget's own heading block while keeping it in the accessibility tree, for pages that already carry the heading. |
|
|
86
|
+
| `suppressPasswordToggle` | `boolean` | `false` | Login | Hides the show/hide button on password fields. |
|
|
87
|
+
| `heading` | `string` | `"Signed in as"` | Session | Heading text override. |
|
|
88
|
+
| `logoutLabel` | `string` | `"Sign out"` | Session | Logout action label override. |
|
|
89
|
+
| `locales` | `Record<string, Partial<Record<string, string>>>` | unset | Login | Copy overrides merged over the builtin dictionaries, keyed by primary language subtag, for example `{ en: { "identifier.title": "Welcome back" } }`. |
|
|
90
|
+
| `lang` | `string` | browser language | Login | BCP-47 language override. |
|
|
91
|
+
|
|
92
|
+
Each widget event reaches the callback in the last column, which receives the event's `detail` payload.
|
|
93
|
+
|
|
94
|
+
| Widget event | Fires when | Detail | Widgets | Callback |
|
|
95
|
+
| --- | --- | --- | --- | --- |
|
|
96
|
+
| `zitadel-flow-step` | Login shows a step, the first one included. | `{ step }` | Login | `onFlowStep` |
|
|
97
|
+
| `zitadel-flow-input` | The visitor edits a field. | `{ name, value }` | Login | `onFlowInput` |
|
|
98
|
+
| `zitadel-flow-complete` | The flow reaches a terminal step. | `{ behavior, redirect_uri?, handoff_token?, handoff_token_expires_at? }` | Login | `onFlowComplete` |
|
|
99
|
+
| `zitadel-flow-redirect` | The widget hands the browser to an identity provider; nobody is signed in yet. | `{ redirect_url, step }` | Login | `onFlowRedirect` |
|
|
100
|
+
| `zitadel-flow-error` | The flow reports an error. | `{ message }` | Login | `onFlowError` |
|
|
101
|
+
| `zitadel-signout` | The user signs out. | `{ display, identifier }` | Logout, Session | `onSignout` |
|
|
102
|
+
|
|
103
|
+
```svelte
|
|
104
|
+
<ZitadelLogin {project} theme="light" onFlowComplete={(detail) => track(detail)} />
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
When your callback for `zitadel-flow-complete`, `zitadel-flow-redirect` or `zitadel-signout` returns a promise, the widget waits for it to settle (up to two seconds) before it navigates.
|
|
108
|
+
|
|
109
|
+
## Read these, don't guess
|
|
110
|
+
|
|
111
|
+
The installed package is authoritative — it and this skill version independently,
|
|
112
|
+
so discover against what is installed rather than trusting anything hardcoded
|
|
113
|
+
here:
|
|
114
|
+
|
|
115
|
+
- `node_modules/@zitadel/sdk-svelte/README.md` — the shipped usage doc.
|
|
116
|
+
- `node_modules/@zitadel/sdk-svelte/dist/index.d.ts` and the component prop
|
|
117
|
+
types (`ZitadelLoginProps`, `ZitadelLogoutProps`, re-exported from
|
|
118
|
+
`@zitadel/sdk-core/types`) — the exact props, their names, and which are
|
|
119
|
+
optional. Read the types before passing a prop you are unsure of.
|
|
120
|
+
|
|
121
|
+
The public exports are `ZitadelLogin`, `ZitadelLogout`, `ZitadelSession`,
|
|
122
|
+
`configureZitadel`, `getApi`, `getZitadelConfig`, `businessLocales`, plus the
|
|
123
|
+
`ZitadelConfig` / `ZitadelProject` types.
|
|
124
|
+
|
|
125
|
+
## Gotchas
|
|
126
|
+
|
|
127
|
+
- **Server rendering.** If your app renders on the server, mount the widget on the client only, after hydration, or pass `projectId` and `proxyPath` to the `ZitadelLogin` wrapper as strings (it writes them as the `project-id` and `proxy-path` attributes; use those hyphenated names only on a raw `<zitadel-login>` element), because a widget that starts before its configuration arrives shows an error instead of the flow.
|
|
128
|
+
- **Production SPA deployment is not yet supported.** The same-origin proxy path
|
|
129
|
+
must come from your hosting platform, and the CLI cannot scaffold those configs
|
|
130
|
+
yet (see ADR 036 and zitadel/nextgen#560). The CLI dev proxy covers local
|
|
131
|
+
development only.
|
|
132
|
+
- **`proxyPath` must reach the backend.** A same-origin path needs a proxy in
|
|
133
|
+
front of your app; without one, point `proxyPath` at the backend origin
|
|
134
|
+
directly (dev only, cross-origin).
|
|
135
|
+
- **Browser web components.** The widgets only start in the browser. A SvelteKit
|
|
136
|
+
server render emits a bare element, so follow the server-rendering gotcha
|
|
137
|
+
above: string `projectId` and `proxyPath` may be server-rendered.
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: zitadel-sdk-sveltekit
|
|
3
|
+
description: >-
|
|
4
|
+
Integrate Zitadel authentication into an existing or custom SvelteKit app with
|
|
5
|
+
@zitadel/sdk-sveltekit. Use when the user wants login, logout, session
|
|
6
|
+
handling, or protected routes in a SvelteKit 3 app and is wiring the SDK
|
|
7
|
+
by hand rather than letting the CLI scaffold a fresh project — adding the
|
|
8
|
+
`handle` hook, reading auth state in a load function, or rendering the
|
|
9
|
+
`ZitadelLogin` / `ZitadelSession` widgets.
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# @zitadel/sdk-sveltekit
|
|
13
|
+
|
|
14
|
+
A SvelteKit `handle` hook and helpers that add Zitadel (Nextgen) auth to a
|
|
15
|
+
SvelteKit app. The hook proxies auth traffic same-origin under `/__nextgen`,
|
|
16
|
+
verifies the session JWT via JWKS on the server, writes the result to
|
|
17
|
+
`event.locals.nextgenAuth`, and redirects unauthenticated requests on protected
|
|
18
|
+
routes. The package is server-only; the widgets come from `@zitadel/sdk-svelte`.
|
|
19
|
+
|
|
20
|
+
## When to use
|
|
21
|
+
|
|
22
|
+
The `zitadel` CLI (`zitadel setup --framework sveltekit`) scaffolds the hook,
|
|
23
|
+
login/register/profile routes, `src/env.ts` and `.env.local` into a fresh or detected
|
|
24
|
+
SvelteKit project — prefer it for greenfield work. Reach for **this skill** when
|
|
25
|
+
you are adding auth to an **existing or custom** SvelteKit app by hand, or
|
|
26
|
+
adjusting a scaffolded wiring.
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pnpm add @zitadel/sdk-sveltekit@latest
|
|
32
|
+
# the login/logout/session widgets are a separate package:
|
|
33
|
+
pnpm add @zitadel/sdk-svelte@latest
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Peer deps: `@sveltejs/kit ^3.0.0`, `svelte ^5.0.0`.
|
|
37
|
+
|
|
38
|
+
## Integrate
|
|
39
|
+
|
|
40
|
+
**1. Server hook.** Declare the settings in `src/env.ts` (SvelteKit 3), so
|
|
41
|
+
SvelteKit serves them from the server-only `$app/env/private` — from
|
|
42
|
+
`.env.local` in dev, from the platform in production. An app that already
|
|
43
|
+
has `src/env.ts` adds the three entries to its own `defineEnvVars` call:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import { defineEnvVars } from '@sveltejs/kit/env';
|
|
47
|
+
|
|
48
|
+
export const variables = defineEnvVars({
|
|
49
|
+
ZITADEL_URL: {},
|
|
50
|
+
ZITADEL_PROJECT_SECRET: {},
|
|
51
|
+
ZITADEL_PROJECT_ID: {},
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Then create or extend `src/hooks.server.ts`:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
import { ZITADEL_PROJECT_ID, ZITADEL_PROJECT_SECRET, ZITADEL_URL } from '$app/env/private';
|
|
59
|
+
import { createNextgenHandle } from '@zitadel/sdk-sveltekit/server';
|
|
60
|
+
|
|
61
|
+
export const handle = createNextgenHandle({
|
|
62
|
+
url: ZITADEL_URL,
|
|
63
|
+
projectSecret: ZITADEL_PROJECT_SECRET,
|
|
64
|
+
projectId: ZITADEL_PROJECT_ID,
|
|
65
|
+
protectedRoutes: ['/admin', '/dashboard*'], // trailing * matches sub-paths
|
|
66
|
+
loginPath: '/login',
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Do not read them from `process.env`: SvelteKit never puts `.env` files there.
|
|
71
|
+
Compose with other hooks via
|
|
72
|
+
`sequence()` from `@sveltejs/kit/hooks`. Sessions count only in the app's own
|
|
73
|
+
project: `projectId`, else `ZITADEL_PROJECT_ID`, else
|
|
74
|
+
`VITE_ZITADEL_PROJECT_ID`. With none set, nobody is signed in.
|
|
75
|
+
|
|
76
|
+
**2. Read auth server-side** with `getAuth(event)` in a load function or
|
|
77
|
+
endpoint, and forward only client-safe fields to the page — never the raw token:
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
import { redirect } from '@sveltejs/kit';
|
|
81
|
+
import { getAuth } from '@zitadel/sdk-sveltekit/server';
|
|
82
|
+
|
|
83
|
+
export const load = (event) => {
|
|
84
|
+
const auth = getAuth(event);
|
|
85
|
+
if (!auth.isAuthenticated) throw redirect(302, '/login');
|
|
86
|
+
return { identifier: auth.session.identifier };
|
|
87
|
+
};
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
`protectedRoutes` only guards full page loads. To keep a page from rendering at
|
|
91
|
+
all without a session, guard it in a `+page.server.ts` load like the one above —
|
|
92
|
+
SvelteKit runs that load on the server for client-side navigation too. A
|
|
93
|
+
universal `+page.ts` load does not work: it runs in the browser, where `locals`
|
|
94
|
+
are not available.
|
|
95
|
+
|
|
96
|
+
**3. Render the widgets** from `@zitadel/sdk-svelte`, mounted on the client only
|
|
97
|
+
(set a flag in `onMount` and wrap the widget in `{#if mounted}`):
|
|
98
|
+
|
|
99
|
+
```svelte
|
|
100
|
+
<script lang="ts">
|
|
101
|
+
import { onMount } from 'svelte';
|
|
102
|
+
import { ZitadelLogin, configureZitadel } from '@zitadel/sdk-svelte';
|
|
103
|
+
|
|
104
|
+
const project = configureZitadel({
|
|
105
|
+
projectId: import.meta.env.VITE_ZITADEL_PROJECT_ID,
|
|
106
|
+
proxyPath: '/__nextgen',
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
let mounted = $state(false);
|
|
110
|
+
onMount(() => (mounted = true));
|
|
111
|
+
</script>
|
|
112
|
+
|
|
113
|
+
{#if mounted}
|
|
114
|
+
<ZitadelLogin {project} purpose="login" postSignInUrl="/admin" />
|
|
115
|
+
{/if}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
`<ZitadelSession {project} postSignOutUrl="/login" />` renders the signed-in
|
|
119
|
+
card with sign-out, and `<ZitadelLogout>` a sign-out control on its own; mount
|
|
120
|
+
them the same way.
|
|
121
|
+
|
|
122
|
+
## Widget props and events
|
|
123
|
+
|
|
124
|
+
This SDK is server-only. The widgets come from `@zitadel/sdk-svelte`, so read its skill for the widget props and events.
|
|
125
|
+
|
|
126
|
+
## Read these, don't guess
|
|
127
|
+
|
|
128
|
+
The package README at `node_modules/@zitadel/sdk-sveltekit/README.md` and the
|
|
129
|
+
bundled `.d.ts` types (`dist/server.d.ts`, `dist/client.d.ts`) are authoritative
|
|
130
|
+
and versioned with the installed package — read them before wiring anything, and
|
|
131
|
+
let them override anything remembered. This skill teaches the pattern, not a
|
|
132
|
+
full catalog of options or the shared JWT-verification pipeline (that lives in
|
|
133
|
+
`@zitadel/sdk-core`). For widget props and callbacks, read
|
|
134
|
+
`node_modules/@zitadel/sdk-svelte/README.md` and its types. Check exact option
|
|
135
|
+
names and defaults against the installed version rather than assuming.
|
|
136
|
+
|
|
137
|
+
## Gotchas
|
|
138
|
+
|
|
139
|
+
- **`@zitadel/sdk-sveltekit` renders no widgets.** Importing `ZitadelLogin` from
|
|
140
|
+
it fails; it comes from `@zitadel/sdk-svelte`.
|
|
141
|
+
- **Mount the widgets client-side only.** Their config is set as element
|
|
142
|
+
properties, which server-rendered markup cannot carry; use `onMount`, not the
|
|
143
|
+
deprecated `$app/environment` (SvelteKit 3).
|
|
144
|
+
- **Keep `App.Locals` declared.** The package merges `nextgenAuth` into it, so
|
|
145
|
+
`src/app.d.ts` must keep the `App` namespace with a `Locals` interface.
|
|
146
|
+
- **Client-side navigation skips the hook.** Without a `+page.server.ts` guard,
|
|
147
|
+
only the `ZitadelSession` card sends a signed-out visitor away.
|