@zitadel/cli 0.2.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.
@@ -0,0 +1,150 @@
1
+ ---
2
+ name: zitadel-sdk-tanstack-start
3
+ description: >-
4
+ Integrate Zitadel authentication into an existing or custom TanStack Start app
5
+ with @zitadel/sdk-tanstack-start. Use when the user wants login, logout,
6
+ session handling, or protected routes in a TanStack Start (React) app and is
7
+ wiring the SDK by hand rather than letting the CLI scaffold a fresh project —
8
+ registering the request middleware in `src/start.ts`, guarding a route with a
9
+ server function, or rendering the `ZitadelLogin` / `ZitadelSession` widgets.
10
+ ---
11
+
12
+ # @zitadel/sdk-tanstack-start
13
+
14
+ TanStack Start request middleware and helpers that add Zitadel (Nextgen) auth to
15
+ a TanStack Start app. The middleware proxies auth traffic same-origin under
16
+ `/__nextgen`, verifies the session JWT via JWKS on the server, places the result
17
+ on the request context as `nextgenAuth`, and redirects unauthenticated requests
18
+ on protected routes. Unlike the other meta-framework SDKs it also ships the
19
+ widgets (a `/react` entry), so no other Zitadel package is needed.
20
+
21
+ ## When to use
22
+
23
+ The `zitadel` CLI (`zitadel setup --framework tanstack-start`) scaffolds
24
+ `src/start.ts`, login/register/profile routes, and `.env.local` into a fresh or
25
+ detected TanStack Start project — prefer it for greenfield work. Reach for
26
+ **this skill** when you are adding auth to an **existing or custom** TanStack
27
+ Start app by hand, or adjusting a scaffolded wiring.
28
+
29
+ ## Install
30
+
31
+ ```bash
32
+ pnpm add @zitadel/sdk-tanstack-start@latest
33
+ ```
34
+
35
+ Peer deps: `@tanstack/react-start >=1.168.10`, `react >=18`, `react-dom >=18`.
36
+
37
+ ## Integrate
38
+
39
+ **1. Request middleware.** Register it in `src/start.ts`, the file TanStack Start
40
+ auto-loads, via `requestMiddleware`. Having this file turns off the automatic
41
+ CSRF protection for server functions, so list `createCsrfMiddleware` before auth:
42
+
43
+ ```ts
44
+ import { createCsrfMiddleware, createMiddleware, createStart } from '@tanstack/react-start';
45
+ import { createNextgenRequestMiddleware } from '@zitadel/sdk-tanstack-start/server';
46
+
47
+ const csrfMiddleware = createCsrfMiddleware({
48
+ filter: (ctx) => ctx.handlerType === 'serverFn',
49
+ });
50
+
51
+ const authMiddleware = createMiddleware({ type: 'request' }).server(
52
+ createNextgenRequestMiddleware({
53
+ url: process.env.ZITADEL_URL,
54
+ projectSecret: process.env.ZITADEL_PROJECT_SECRET,
55
+ protectedRoutes: ['/admin', '/dashboard*'], // trailing * matches sub-paths
56
+ loginPath: '/login',
57
+ }),
58
+ );
59
+
60
+ export const startInstance = createStart(() => ({
61
+ requestMiddleware: [csrfMiddleware, authMiddleware],
62
+ }));
63
+ ```
64
+
65
+ Sessions count only in the app's own project: `projectId`, else
66
+ `ZITADEL_PROJECT_ID`, else `VITE_ZITADEL_PROJECT_ID`. With none set, nobody is
67
+ signed in.
68
+
69
+ The same proxy/verify/protect decision is exported as the framework-agnostic
70
+ `handleNextgenRequest(request, options)` for a custom server entry.
71
+
72
+ **2. Read auth and guard routes through a server function.** Server functions
73
+ receive the middleware's context; a route's `beforeLoad` does not, and on
74
+ client-side navigation it runs in the browser. Call a server function from
75
+ `beforeLoad`:
76
+
77
+ ```ts
78
+ import { createServerFn } from '@tanstack/react-start';
79
+ import { createFileRoute, redirect } from '@tanstack/react-router';
80
+ import { getAuth } from '@zitadel/sdk-tanstack-start/server';
81
+
82
+ // A server function's return value is serialised to the browser, so return
83
+ // only client-safe fields: `getAuth` also carries the raw session token.
84
+ const fetchAuth = createServerFn().handler(({ context }) => {
85
+ const auth = getAuth(context);
86
+ return auth.isAuthenticated
87
+ ? { isAuthenticated: true as const, userId: auth.session.userId }
88
+ : { isAuthenticated: false as const };
89
+ });
90
+
91
+ export const Route = createFileRoute('/admin')({
92
+ beforeLoad: async () => {
93
+ const auth = await fetchAuth();
94
+ if (!auth.isAuthenticated) throw redirect({ to: '/login' });
95
+ return { userId: auth.userId };
96
+ },
97
+ });
98
+ ```
99
+
100
+ **3. Render the widgets** from the `/react` entry, with `configureZitadel` from
101
+ `/client`:
102
+
103
+ ```tsx
104
+ import { ZitadelLogin } from '@zitadel/sdk-tanstack-start/react';
105
+ import { configureZitadel } from '@zitadel/sdk-tanstack-start/client';
106
+
107
+ const project = configureZitadel({
108
+ projectId: import.meta.env.VITE_ZITADEL_PROJECT_ID,
109
+ proxyPath: '/__nextgen',
110
+ });
111
+
112
+ export function LoginPage() {
113
+ return <ZitadelLogin project={project} purpose="login" postSignInUrl="/admin" />;
114
+ }
115
+ ```
116
+
117
+ `<ZitadelSession project={project} postSignOutUrl="/login" />` renders the
118
+ signed-in card with sign-out, and `<ZitadelLogout>` a sign-out control on its own.
119
+
120
+ ## Widget props and events
121
+
122
+ This SDK is not server-only: its `/react` entry wraps the widgets from `@zitadel/sdk-react`, so no other package is needed. Read the `@zitadel/sdk-react` skill for the widget props and events.
123
+
124
+ ## Read these, don't guess
125
+
126
+ The package README at `node_modules/@zitadel/sdk-tanstack-start/README.md` and
127
+ the bundled `.d.ts` types (`dist/server.d.ts`, `dist/client.d.ts`,
128
+ `dist/react.d.ts`) are authoritative and versioned with the installed package —
129
+ read them before wiring anything, and let them override anything remembered.
130
+ This skill teaches the pattern, not a full catalog of options, widget props, or
131
+ the shared JWT-verification pipeline (that lives in `@zitadel/sdk-core`). Check
132
+ exact option names, props, and defaults against the installed version rather
133
+ than assuming.
134
+
135
+ ## Gotchas
136
+
137
+ - **Import widgets from `/react`, not `/client`.** `/client` only configures the
138
+ SDK and exports no components.
139
+ - **The widgets render nothing on the server and during hydration.** They mount
140
+ right after, with every prop in place; do not expect them in the SSR markup.
141
+ - **Keep `createCsrfMiddleware` ahead of auth.** `src/start.ts` opts the app out
142
+ of TanStack Start's automatic CSRF protection.
143
+ - **`beforeLoad` has no `nextgenAuth`.** Read it with `getAuth(context)` inside a
144
+ server function, not from the route context.
145
+ - **Never return `getAuth(context)` itself from a server function.** Its session
146
+ carries the raw token, and a server function's result reaches browser scripts.
147
+ Return only `userId` and other client-safe fields.
148
+ - **`protectedRoutes` only guards full document requests.** Client-side `<Link>`
149
+ navigation needs the `beforeLoad` server-function guard; without it only the
150
+ `ZitadelSession` card sends a signed-out visitor away.
@@ -0,0 +1,147 @@
1
+ ---
2
+ name: zitadel-sdk-vue
3
+ description: >-
4
+ Integrate Zitadel authentication into a Vue 3 single-page app with
5
+ @zitadel/sdk-vue. Use when the user wants to add Zitadel login, logout, or a
6
+ signed-in session card to an existing or custom Vue/Vite SPA — wiring the
7
+ configureZitadel handle, the ZitadelLogin / ZitadelLogout / ZitadelSession
8
+ components, the same-origin backend proxy, and post-sign-in / post-sign-out
9
+ redirects.
10
+ ---
11
+
12
+ # @zitadel/sdk-vue
13
+
14
+ `@zitadel/sdk-vue` provides Vue 3 components wrapping the Zitadel auth UI web
15
+ components (`ZitadelLogin`, `ZitadelLogout`, `ZitadelSession`) for client-side
16
+ SPAs (Vite, etc.). You configure one project handle with `configureZitadel(...)`
17
+ and hand it to the components; they talk to the backend over a same-origin
18
+ proxy path.
19
+
20
+ ## When to use
21
+
22
+ Reach for this skill when integrating Zitadel into an **existing or custom** Vue
23
+ app, where you are adding the components by hand.
24
+
25
+ For a **fresh** scaffold, prefer the CLI instead — it wires the proxy, env, and
26
+ components for you:
27
+
28
+ ```sh
29
+ npx @zitadel/cli@latest setup --framework vue --non-interactive --json
30
+ ```
31
+
32
+ Use this skill when `setup` is not appropriate (an app with its own structure,
33
+ a partial integration, or customizing what the CLI produced).
34
+
35
+ ## Install
36
+
37
+ ```sh
38
+ npm install @zitadel/sdk-vue@latest
39
+ ```
40
+
41
+ Peer dependencies: `vue >=3.2`. Requires TypeScript ≥ 5.0 (the published types use `export type *`).
42
+
43
+ ## Integrate
44
+
45
+ Configure once with `configureZitadel(...)`, then pass the returned handle as
46
+ `:project` to each component. The components register the underlying web
47
+ components on import — no Vue plugin or `app.use(...)` is needed.
48
+
49
+ ```vue
50
+ <script setup lang="ts">
51
+ import { ZitadelLogin, configureZitadel } from '@zitadel/sdk-vue';
52
+
53
+ const project = configureZitadel({
54
+ projectId: import.meta.env.VITE_ZITADEL_PROJECT_ID,
55
+ proxyPath: '/__nextgen',
56
+ });
57
+ </script>
58
+
59
+ <template>
60
+ <ZitadelLogin :project="project" purpose="login" postSignInUrl="/" />
61
+ </template>
62
+ ```
63
+
64
+ Logout and the signed-in session card take the same `:project` handle:
65
+
66
+ ```vue
67
+ <ZitadelLogout :project="project" postSignOutUrl="/login" />
68
+ <ZitadelSession :project="project" />
69
+ ```
70
+
71
+ - `purpose` on `ZitadelLogin` is `"login"` by default (also accepts the other
72
+ flow purposes, e.g. registration).
73
+ - `postSignInUrl` / `postSignOutUrl` are where the browser lands after the flow.
74
+ - The widgets call `${proxyPath}/…` **same-origin** (default `/__nextgen`), so
75
+ your host must proxy that path to the Zitadel backend. For local development
76
+ you can instead point `proxyPath` straight at the backend cross-origin, e.g.
77
+ `proxyPath: 'http://localhost:8080'` (the `zitadel start` local runtime port).
78
+
79
+ ## Widget props and events
80
+
81
+ `ZitadelLogin`, `ZitadelLogout` and `ZitadelSession` take the props below, spelled the same in every SPA SDK. An unset prop keeps the widget's own default.
82
+
83
+ | Prop | Type | Default | Widgets | Description |
84
+ | --- | --- | --- | --- | --- |
85
+ | `project` | `ZitadelProject` | unset | Login, Logout, Session | The handle from `configureZitadel(...)`. Wins over `projectId` and `proxyPath`. |
86
+ | `projectId` | `string` | unset | Login, Logout, Session | Project id, read when no `project` handle is passed. |
87
+ | `proxyPath` | `string` | `"/__nextgen"` | Login, Logout, Session | Same-origin path the widget calls. |
88
+ | `purpose` | `CreateFlowBodyPurpose` | `"login"` | Login | Flow purpose. |
89
+ | `flowName` | `string` | unset | Login | Runs the flow definition with this `name`; unset runs the project's default flow for the purpose. |
90
+ | `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. |
91
+ | `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. |
92
+ | `postSignOutUrl` | `string` | unset | Logout, Session | Where to navigate after sign-out. |
93
+ | `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. |
94
+ | `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. |
95
+ | `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`. |
96
+ | `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. |
97
+ | `suppressPasswordToggle` | `boolean` | `false` | Login | Hides the show/hide button on password fields. |
98
+ | `heading` | `string` | `"Signed in as"` | Session | Heading text override. |
99
+ | `logoutLabel` | `string` | `"Sign out"` | Session | Logout action label override. |
100
+ | `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" } }`. |
101
+ | `lang` | `string` | browser language | Login | BCP-47 language override. |
102
+
103
+ Each widget event reaches the callback in the last column, which receives the event's `detail` payload.
104
+
105
+ | Widget event | Fires when | Detail | Widgets | Callback |
106
+ | --- | --- | --- | --- | --- |
107
+ | `zitadel-flow-step` | Login shows a step, the first one included. | `{ step }` | Login | `@flowStep` |
108
+ | `zitadel-flow-input` | The visitor edits a field. | `{ name, value }` | Login | `@flowInput` |
109
+ | `zitadel-flow-complete` | The flow reaches a terminal step. | `{ behavior, redirect_uri?, handoff_token?, handoff_token_expires_at? }` | Login | `@flowComplete` |
110
+ | `zitadel-flow-redirect` | The widget hands the browser to an identity provider; nobody is signed in yet. | `{ redirect_url, step }` | Login | `@flowRedirect` |
111
+ | `zitadel-flow-error` | The flow reports an error. | `{ message }` | Login | `@flowError` |
112
+ | `zitadel-signout` | The user signs out. | `{ display, identifier }` | Logout, Session | `@signout` |
113
+
114
+ ```vue
115
+ <ZitadelLogin :project="project" theme="light" @flowComplete="track" />
116
+ ```
117
+
118
+ The `zitadel-flow-complete`, `zitadel-flow-redirect` and `zitadel-signout` details carry a `waitUntil(promise)`; call it from your handler to make the widget wait for your async work before it navigates.
119
+
120
+ ## Read these, don't guess
121
+
122
+ The SDK and this skill version independently — discover the real surface before
123
+ writing code, and treat it as authoritative over anything here:
124
+
125
+ - `node_modules/@zitadel/sdk-vue/README.md` — the installed README.
126
+ - `node_modules/@zitadel/sdk-vue/dist/index.d.ts` — the TypeScript types: the
127
+ exact exports and every component prop. The public exports are
128
+ `ZitadelLogin`, `ZitadelLogout`, `ZitadelSession`, `configureZitadel`,
129
+ `getApi`, `getZitadelConfig`, the `ZitadelConfig` / `ZitadelProject` types,
130
+ and `businessLocales`.
131
+
132
+ Check the installed version's props rather than assuming; emitted events and
133
+ optional props (`locales`, `lang`, `theme`, `variant`, `suppressHeader`, …)
134
+ evolve.
135
+
136
+ ## Gotchas
137
+
138
+ - **Server rendering.** If your app renders on the server, mount the widget on the client only, after hydration (the `ZitadelLogin` wrapper sets `projectId` and `proxyPath` as element properties, so adding them to the wrapper does not put them in server markup), or use a raw `<zitadel-login>` element with `project-id` and `proxy-path` as attributes, because a widget that starts before its configuration arrives shows an error instead of the flow.
139
+ - **Production SPA deployment is not yet supported.** The same-origin proxy path
140
+ must come from your hosting platform, and the CLI cannot scaffold those host
141
+ configs yet (see ADR 036 and zitadel/nextgen#560). The CLI dev proxy covers
142
+ local development only.
143
+ - **Same-origin by default.** Unless you override `proxyPath`, the widgets
144
+ expect `/__nextgen` to be proxied to the backend on the same origin — a bare
145
+ SPA with no proxy will fail its auth calls.
146
+ - **TypeScript ≥ 5.0 is required**; older compilers choke on the `export type *`
147
+ re-exports in the published type definitions.