@zitadel/sdk-nuxt 0.1.0-alpha.9 → 1.0.0-alpha.21
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 +100 -74
- package/dist/{chunk-E7GMYXBM.js → chunk-GQKD27DF.js} +38 -49
- package/dist/index.d.ts +2 -3
- package/dist/index.js +3 -1
- package/dist/module.js +27 -1
- package/dist/runtime/plugin.js +4 -8
- package/dist/runtime/server/handler.js +1 -1
- package/dist/runtime/server/middleware.d.ts +2 -2
- package/dist/runtime/server/middleware.js +1 -1
- package/dist/runtime/types.d.ts +1 -37
- package/dist/server.d.ts +1 -1
- package/dist/server.js +1 -1
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @zitadel/sdk-nuxt
|
|
2
2
|
|
|
3
|
-
Nuxt middleware and helpers for Nextgen Auth.
|
|
3
|
+
Nuxt module, Nitro middleware, and helpers for Nextgen Auth.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -8,78 +8,97 @@ Nuxt middleware and helpers for Nextgen Auth.
|
|
|
8
8
|
pnpm add @zitadel/sdk-nuxt
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
There are two ways to wire the SDK. **The module is what `zitadel setup`
|
|
12
|
+
scaffolds** and the recommended path; the direct-middleware surface remains
|
|
13
|
+
for hand-rolled setups.
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
## Surface 1 — the Nuxt module (recommended, CLI-scaffolded)
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const { nextgen } = useRuntimeConfig();
|
|
21
|
-
|
|
22
|
-
export default createNextgenMiddleware({
|
|
23
|
-
url: nextgen.url,
|
|
24
|
-
protectedRoutes: ['/admin', '/dashboard*'],
|
|
25
|
-
loginPath: '/login',
|
|
26
|
-
});
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
The middleware runs on every request and does three things in one pass:
|
|
30
|
-
|
|
31
|
-
1. **Proxies** `/__nextgen/*` requests to the auth backend
|
|
32
|
-
2. **Verifies** the session JWT via JWKS using the Web Crypto API
|
|
33
|
-
3. **Redirects** unauthenticated requests to `loginPath` for protected routes
|
|
34
|
-
|
|
35
|
-
Add the issuer URL to `nuxt.config.ts`:
|
|
17
|
+
Register the module under the `nextgen` config key, and give the client
|
|
18
|
+
plugin your project id via `runtimeConfig.public.zitadelProjectId` — without
|
|
19
|
+
it the plugin skips `configureZitadel()`, `useZitadelProject()` returns
|
|
20
|
+
`null`, and the login widget cannot initialize:
|
|
36
21
|
|
|
37
22
|
```ts
|
|
38
23
|
export default defineNuxtConfig({
|
|
24
|
+
modules: ['@zitadel/sdk-nuxt/module'],
|
|
25
|
+
nextgen: {
|
|
26
|
+
url: process.env.ZITADEL_URL ?? 'http://localhost:8080',
|
|
27
|
+
protectedRoutes: ['/admin', '/dashboard*'],
|
|
28
|
+
loginPath: '/login',
|
|
29
|
+
},
|
|
39
30
|
runtimeConfig: {
|
|
40
|
-
|
|
41
|
-
|
|
31
|
+
public: {
|
|
32
|
+
zitadelProjectId: process.env.NUXT_PUBLIC_ZITADEL_PROJECT_ID ?? '',
|
|
42
33
|
},
|
|
43
34
|
},
|
|
44
35
|
});
|
|
45
36
|
```
|
|
46
37
|
|
|
47
|
-
|
|
38
|
+
(This mirrors what `zitadel setup` writes into `nuxt.config.ts`.)
|
|
48
39
|
|
|
49
|
-
|
|
40
|
+
The module registers the Nitro server middleware, the auth plugin (which
|
|
41
|
+
seeds server-side auth state, hydrates it on the client, and calls
|
|
42
|
+
`configureZitadel()` from the runtime config above), and auto-imports the
|
|
43
|
+
composables — no `server/middleware/auth.ts`, no manual plugin.
|
|
50
44
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
};
|
|
60
|
-
useState('nextgen-auth', () => auth);
|
|
61
|
-
});
|
|
62
|
-
```
|
|
45
|
+
### Module options (what the module actually forwards)
|
|
46
|
+
|
|
47
|
+
| Option | Type | Default | Description |
|
|
48
|
+
| --- | --- | --- | --- |
|
|
49
|
+
| `url` | `string` | `ZITADEL_URL` env, else `http://localhost:8080` | Full URL of the Zitadel auth backend |
|
|
50
|
+
| `proxyPath` | `string` | `"/__nextgen"` | The path the **client** widgets call (exposed via public runtime config). The registered server handler currently always serves `/__nextgen` regardless of this option — to actually move the server prefix, use the direct-middleware surface |
|
|
51
|
+
| `protectedRoutes` | `string[]` | `[]` | Paths requiring a valid session. Trailing `*` matches sub-paths |
|
|
52
|
+
| `loginPath` | `string` | `"/login"` | Where to redirect unauthenticated users |
|
|
63
53
|
|
|
64
|
-
|
|
54
|
+
The module's registered handler reads only `url`, `protectedRoutes`, and
|
|
55
|
+
`loginPath` from runtime config; `proxyPath` configures the client side only
|
|
56
|
+
(see its row above). The fine-tuning options of the direct-middleware surface
|
|
57
|
+
(`ignoredRoutes`, `allowedAlgorithms`, `allowedTokenTypes`, `clockSkewMs`,
|
|
58
|
+
`jwksTimeoutMs`, `opaqueTokenTimeoutMs`, `proxyTimeoutMs`, `audience`) are
|
|
59
|
+
**not currently forwarded by the module** — if you need them, use Surface 2.
|
|
60
|
+
The module also loads the server-only project secret into runtime config at
|
|
61
|
+
startup, from the `ZITADEL_PROJECT_SECRET` environment variable or the
|
|
62
|
+
scaffolded `.env.local`.
|
|
63
|
+
|
|
64
|
+
### Reading auth state
|
|
65
|
+
|
|
66
|
+
`useAuth()` is auto-imported:
|
|
65
67
|
|
|
66
68
|
```vue
|
|
67
69
|
<script setup lang="ts">
|
|
68
|
-
const auth =
|
|
69
|
-
if (auth.value?.isAuthenticated) {
|
|
70
|
-
await navigateTo('/admin');
|
|
71
|
-
}
|
|
70
|
+
const auth = useAuth();
|
|
72
71
|
</script>
|
|
73
72
|
|
|
74
73
|
<template>
|
|
75
|
-
<p>{{ auth.isAuthenticated ? auth.session.
|
|
74
|
+
<p>{{ auth.isAuthenticated ? (auth.session.display ?? auth.session.identifier) : 'Not signed in' }}</p>
|
|
76
75
|
</template>
|
|
77
76
|
```
|
|
78
77
|
|
|
79
|
-
|
|
78
|
+
The returned state intentionally omits the raw JWT — use `getAuth(event)` in
|
|
79
|
+
a server route when you need the token to call upstream APIs:
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
import { getAuth } from '@zitadel/sdk-nuxt/server';
|
|
83
|
+
|
|
84
|
+
export default defineEventHandler((event) => {
|
|
85
|
+
const auth = getAuth(event);
|
|
86
|
+
if (!auth.isAuthenticated) throw createError({ statusCode: 401 });
|
|
87
|
+
return { userId: auth.session.userId };
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Login page
|
|
92
|
+
|
|
93
|
+
Register the shared components in a client-only plugin
|
|
94
|
+
(`plugins/zitadel-components.client.ts` — do **not** import
|
|
95
|
+
`@zitadel/components` from page `<script setup>`, that runs during SSR).
|
|
96
|
+
Under strict package managers (pnpm, Yarn PnP) `@zitadel/components` is not
|
|
97
|
+
resolvable as a transitive dependency, so declare it in your app first:
|
|
80
98
|
|
|
81
|
-
|
|
82
|
-
|
|
99
|
+
```bash
|
|
100
|
+
pnpm add @zitadel/components
|
|
101
|
+
```
|
|
83
102
|
|
|
84
103
|
```ts
|
|
85
104
|
import "@zitadel/components";
|
|
@@ -87,37 +106,48 @@ import "@zitadel/components";
|
|
|
87
106
|
export default defineNuxtPlugin(() => {});
|
|
88
107
|
```
|
|
89
108
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
`
|
|
93
|
-
|
|
94
|
-
### 5. Login page
|
|
95
|
-
|
|
96
|
-
Render `<zitadel-login>` inside `<ClientOnly>`:
|
|
109
|
+
Then render `<zitadel-login>` inside `<ClientOnly>`, binding the project
|
|
110
|
+
handle from the auto-imported `useZitadelProject()` composable — there is no
|
|
111
|
+
`api-base` attribute:
|
|
97
112
|
|
|
98
113
|
```vue
|
|
114
|
+
<script setup lang="ts">
|
|
115
|
+
const project = useZitadelProject();
|
|
116
|
+
</script>
|
|
117
|
+
|
|
99
118
|
<template>
|
|
100
119
|
<main>
|
|
101
120
|
<ClientOnly>
|
|
102
|
-
<zitadel-login
|
|
121
|
+
<zitadel-login :project="project" post-sign-in-url="/admin" />
|
|
103
122
|
</ClientOnly>
|
|
104
123
|
</main>
|
|
105
124
|
</template>
|
|
106
125
|
```
|
|
107
126
|
|
|
108
|
-
|
|
127
|
+
## Surface 2 — direct middleware (hand-rolled)
|
|
128
|
+
|
|
129
|
+
Create `server/middleware/auth.ts` yourself when you need the full option
|
|
130
|
+
set:
|
|
109
131
|
|
|
110
132
|
```ts
|
|
111
|
-
import {
|
|
133
|
+
import { createNextgenMiddleware } from '@zitadel/sdk-nuxt/server';
|
|
112
134
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
135
|
+
const { nextgen } = useRuntimeConfig();
|
|
136
|
+
|
|
137
|
+
export default createNextgenMiddleware({
|
|
138
|
+
url: nextgen.url,
|
|
139
|
+
protectedRoutes: ['/admin', '/dashboard*'],
|
|
140
|
+
loginPath: '/login',
|
|
117
141
|
});
|
|
118
142
|
```
|
|
119
143
|
|
|
120
|
-
|
|
144
|
+
The middleware runs on every request and does three things in one pass:
|
|
145
|
+
|
|
146
|
+
1. **Proxies** `/__nextgen/*` requests to the auth backend
|
|
147
|
+
2. **Verifies** the session JWT via JWKS using the Web Crypto API
|
|
148
|
+
3. **Redirects** unauthenticated requests to `loginPath` for protected routes
|
|
149
|
+
|
|
150
|
+
### Direct-middleware options
|
|
121
151
|
|
|
122
152
|
| Option | Type | Default | Description |
|
|
123
153
|
| ------------------- | -------------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -130,17 +160,13 @@ export default defineEventHandler((event) => {
|
|
|
130
160
|
| `allowedTokenTypes` | `string[]` | `["JWT", "at+JWT"]` | Accepted `typ` header values (case-insensitive). Set to `[]` to disable this check |
|
|
131
161
|
| `clockSkewMs` | `number` | `5000` | Clock skew tolerance in ms for `exp`, `nbf`, `iat` |
|
|
132
162
|
| `jwksTimeoutMs` | `number` | `5000` | Timeout in ms for JWKS endpoint requests. Token is rejected if the fetch exceeds this window |
|
|
163
|
+
| `opaqueTokenTimeoutMs` | `number` | `5000` | Timeout in ms for opaque (non-JWT) session validation via `GET /sessions/me` |
|
|
164
|
+
| `proxyTimeoutMs` | `number` | `5000` | Timeout in ms for upstream proxy requests; requests exceeding it abort with a network error |
|
|
133
165
|
| `audience` | `string \| string[]` | not validated | Expected `aud` claim value(s). When omitted, audience is not checked |
|
|
134
166
|
|
|
135
167
|
## How JWT verification works
|
|
136
168
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
5. The public key is fetched from `{url}/auth/keys` (JWKS) using the Web Crypto API, with a 5 s timeout, and cached for 5 minutes per `kid`
|
|
142
|
-
6. The signature is verified **before** any claim checks
|
|
143
|
-
7. `iss` must be present and must equal `url` — tokens without an issuer are rejected
|
|
144
|
-
8. `exp` must be present and must be in the future (with `clockSkewMs` tolerance) — tokens without an expiry are rejected
|
|
145
|
-
9. `nbf` and `iat` are validated with `clockSkewMs` tolerance when present
|
|
146
|
-
10. The `x-nextgen-auth-token` header is stripped from all proxied requests to prevent internal state leakage
|
|
169
|
+
The verification pipeline is shared across SDKs and documented once in
|
|
170
|
+
[`@zitadel/sdk-core`](https://github.com/zitadel/nextgen/tree/main/packages/sdk-core#how-jwt-verification-works).
|
|
171
|
+
On top of it, the Nitro middleware strips the `x-nextgen-auth-token` header
|
|
172
|
+
from all proxied requests to prevent internal state leakage.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/runtime/server/middleware.ts
|
|
2
|
+
import { useRuntimeConfig } from "#imports";
|
|
2
3
|
import {
|
|
3
4
|
HOP_BY_HOP,
|
|
4
5
|
INTERNAL_HEADERS,
|
|
@@ -17,12 +18,7 @@ import {
|
|
|
17
18
|
} from "h3";
|
|
18
19
|
|
|
19
20
|
// src/runtime/lib/jwt.ts
|
|
20
|
-
import {
|
|
21
|
-
JWKS_TTL_MS,
|
|
22
|
-
base64UrlDecode,
|
|
23
|
-
decodeJwt,
|
|
24
|
-
verifyJwt
|
|
25
|
-
} from "@zitadel/sdk-core/jwt";
|
|
21
|
+
import { JWKS_TTL_MS, base64UrlDecode, decodeJwt, verifyJwt } from "@zitadel/sdk-core/jwt";
|
|
26
22
|
|
|
27
23
|
// src/runtime/server/middleware.ts
|
|
28
24
|
function buildUpstreamHeaders(event) {
|
|
@@ -38,10 +34,7 @@ function buildUpstreamHeaders(event) {
|
|
|
38
34
|
const socketIp = event.node.req.socket?.remoteAddress;
|
|
39
35
|
if (socketIp) {
|
|
40
36
|
const existingXff = headers.get("x-forwarded-for");
|
|
41
|
-
headers.set(
|
|
42
|
-
"x-forwarded-for",
|
|
43
|
-
existingXff ? `${existingXff}, ${socketIp}` : socketIp
|
|
44
|
-
);
|
|
37
|
+
headers.set("x-forwarded-for", existingXff ? `${existingXff}, ${socketIp}` : socketIp);
|
|
45
38
|
}
|
|
46
39
|
if (!headers.has("x-forwarded-host")) {
|
|
47
40
|
headers.set("x-forwarded-host", url.host);
|
|
@@ -64,8 +57,7 @@ function createNextgenMiddleware(options = {}) {
|
|
|
64
57
|
allowedTokenTypes = ["JWT", "at+JWT"],
|
|
65
58
|
jwksTimeoutMs,
|
|
66
59
|
proxyTimeoutMs = 5e3,
|
|
67
|
-
opaqueTokenTimeoutMs = 5e3
|
|
68
|
-
onExchangeResponse
|
|
60
|
+
opaqueTokenTimeoutMs = 5e3
|
|
69
61
|
} = options;
|
|
70
62
|
if (!loginPath.startsWith("/") || loginPath.startsWith("//")) {
|
|
71
63
|
throw new Error(
|
|
@@ -80,14 +72,7 @@ function createNextgenMiddleware(options = {}) {
|
|
|
80
72
|
return;
|
|
81
73
|
}
|
|
82
74
|
if (pathname === proxyPath || pathname.startsWith(`${proxyPath}/`)) {
|
|
83
|
-
return proxyRequest(
|
|
84
|
-
event,
|
|
85
|
-
url,
|
|
86
|
-
proxyPath,
|
|
87
|
-
urlObj,
|
|
88
|
-
proxyTimeoutMs,
|
|
89
|
-
onExchangeResponse
|
|
90
|
-
);
|
|
75
|
+
return proxyRequest(event, url, proxyPath, urlObj, proxyTimeoutMs);
|
|
91
76
|
}
|
|
92
77
|
return handleAuth(event, {
|
|
93
78
|
url,
|
|
@@ -103,7 +88,7 @@ function createNextgenMiddleware(options = {}) {
|
|
|
103
88
|
});
|
|
104
89
|
});
|
|
105
90
|
}
|
|
106
|
-
async function proxyRequest(event, authUrl, proxyPath, url, proxyTimeoutMs
|
|
91
|
+
async function proxyRequest(event, authUrl, proxyPath, url, proxyTimeoutMs) {
|
|
107
92
|
const suffix = url.pathname.slice(proxyPath.length);
|
|
108
93
|
const target = `${authUrl}${suffix}${url.search}`;
|
|
109
94
|
const method = event.node.req.method ?? "GET";
|
|
@@ -111,11 +96,11 @@ async function proxyRequest(event, authUrl, proxyPath, url, proxyTimeoutMs, onEx
|
|
|
111
96
|
const rawBody = hasBody ? await readRawBody(event, false) : void 0;
|
|
112
97
|
const body = rawBody != null ? new Uint8Array(rawBody) : void 0;
|
|
113
98
|
const upstreamHeaders = buildUpstreamHeaders(event);
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const
|
|
117
|
-
if (
|
|
118
|
-
upstreamHeaders.set("authorization", `Bearer
|
|
99
|
+
if (requiresProjectSecret(method, suffix) && !upstreamHeaders.has("authorization")) {
|
|
100
|
+
const config = useRuntimeConfig();
|
|
101
|
+
const projectSecret = config.nextgen?.projectSecret;
|
|
102
|
+
if (projectSecret) {
|
|
103
|
+
upstreamHeaders.set("authorization", `Bearer ${projectSecret}`);
|
|
119
104
|
}
|
|
120
105
|
}
|
|
121
106
|
const upstream = await fetch(target, {
|
|
@@ -130,14 +115,10 @@ async function proxyRequest(event, authUrl, proxyPath, url, proxyTimeoutMs, onEx
|
|
|
130
115
|
for (const cookie of setCookieHeaders) {
|
|
131
116
|
responseHeaders.append("set-cookie", cookie);
|
|
132
117
|
}
|
|
133
|
-
|
|
118
|
+
const response = new Response(upstream.body, {
|
|
134
119
|
status: upstream.status,
|
|
135
120
|
headers: responseHeaders
|
|
136
121
|
});
|
|
137
|
-
const isExchange = method === "POST" && suffix.startsWith("/sessions/exchange");
|
|
138
|
-
if (isExchange && onExchangeResponse) {
|
|
139
|
-
response = await onExchangeResponse(response);
|
|
140
|
-
}
|
|
141
122
|
event.node.res.statusCode = response.status;
|
|
142
123
|
for (const [key, value] of response.headers.entries()) {
|
|
143
124
|
if (key.toLowerCase() === "set-cookie") continue;
|
|
@@ -149,14 +130,15 @@ async function proxyRequest(event, authUrl, proxyPath, url, proxyTimeoutMs, onEx
|
|
|
149
130
|
}
|
|
150
131
|
return response.body;
|
|
151
132
|
}
|
|
133
|
+
function requiresProjectSecret(method, pathname) {
|
|
134
|
+
return method.toUpperCase() === "POST" && pathname === "/sessions/exchange";
|
|
135
|
+
}
|
|
152
136
|
var DECODER = new TextDecoder();
|
|
153
137
|
function isJwtShaped(token) {
|
|
154
138
|
const parts = token.split(".");
|
|
155
139
|
if (parts.length < 3 || !parts[0]) return false;
|
|
156
140
|
try {
|
|
157
|
-
const header = JSON.parse(
|
|
158
|
-
DECODER.decode(base64UrlDecode(parts[0]))
|
|
159
|
-
);
|
|
141
|
+
const header = JSON.parse(DECODER.decode(base64UrlDecode(parts[0])));
|
|
160
142
|
return typeof header?.alg === "string" && !("enc" in header);
|
|
161
143
|
} catch {
|
|
162
144
|
return false;
|
|
@@ -171,7 +153,12 @@ async function validateOpaqueSessionToken(token, issuerUrl, timeoutMs) {
|
|
|
171
153
|
});
|
|
172
154
|
if (!res.ok) return null;
|
|
173
155
|
const body = await res.json();
|
|
174
|
-
return {
|
|
156
|
+
return {
|
|
157
|
+
userId: body.user_id,
|
|
158
|
+
identifier: body.user?.identifier ?? null,
|
|
159
|
+
identifierProperty: body.user?.identifier_property ?? null,
|
|
160
|
+
display: body.user?.display ?? null
|
|
161
|
+
};
|
|
175
162
|
} catch {
|
|
176
163
|
return null;
|
|
177
164
|
}
|
|
@@ -207,36 +194,38 @@ async function handleAuth(event, opts) {
|
|
|
207
194
|
isAuthenticated: true,
|
|
208
195
|
session: {
|
|
209
196
|
userId: payload.sub,
|
|
210
|
-
|
|
211
|
-
|
|
197
|
+
identifier: payload.email ?? null,
|
|
198
|
+
identifierProperty: null,
|
|
199
|
+
display: payload.name ?? null,
|
|
212
200
|
token
|
|
213
201
|
}
|
|
214
202
|
};
|
|
215
203
|
return;
|
|
216
204
|
}
|
|
205
|
+
let liveAnonymousSession = false;
|
|
217
206
|
if (!payload && cookieToken && !isJwtShaped(cookieToken)) {
|
|
218
|
-
const opaqueResult = await validateOpaqueSessionToken(
|
|
219
|
-
|
|
220
|
-
url,
|
|
221
|
-
opaqueTokenTimeoutMs
|
|
222
|
-
);
|
|
223
|
-
if (opaqueResult) {
|
|
207
|
+
const opaqueResult = await validateOpaqueSessionToken(cookieToken, url, opaqueTokenTimeoutMs);
|
|
208
|
+
if (opaqueResult?.userId) {
|
|
224
209
|
event.context.nextgenAuth = {
|
|
225
210
|
isAuthenticated: true,
|
|
226
211
|
session: {
|
|
227
|
-
userId: opaqueResult.userId
|
|
228
|
-
|
|
229
|
-
|
|
212
|
+
userId: opaqueResult.userId,
|
|
213
|
+
identifier: opaqueResult.identifier,
|
|
214
|
+
identifierProperty: opaqueResult.identifierProperty,
|
|
215
|
+
display: opaqueResult.display,
|
|
230
216
|
token: cookieToken
|
|
231
217
|
}
|
|
232
218
|
};
|
|
233
219
|
return;
|
|
234
220
|
}
|
|
221
|
+
liveAnonymousSession = opaqueResult !== null;
|
|
235
222
|
}
|
|
236
223
|
event.context.nextgenAuth = { isAuthenticated: false, session: null };
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
224
|
+
if (!liveAnonymousSession) {
|
|
225
|
+
for (const name of Object.keys(parseCookies(event))) {
|
|
226
|
+
if (name.startsWith("__nextgen")) {
|
|
227
|
+
deleteCookie(event, name);
|
|
228
|
+
}
|
|
240
229
|
}
|
|
241
230
|
}
|
|
242
231
|
if (matchesRoutes(pathname, protectedRoutes)) {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
export { ZitadelLogin, ZitadelLogout } from '@zitadel/components';
|
|
1
|
+
export { ZitadelLogin, ZitadelLogout, businessLocales } from '@zitadel/components';
|
|
2
2
|
export { createNextgenMiddleware, getAuth } from './runtime/server/middleware.js';
|
|
3
3
|
import { ZitadelProject } from '@zitadel/api/config';
|
|
4
|
-
export { ClientAuthResult } from '
|
|
5
|
-
export { AuthResult, NextgenMiddlewareOptions } from '@zitadel/sdk-core/types';
|
|
4
|
+
export { AuthResult, ClientAuthResult, NextgenMiddlewareOptions } from '@zitadel/sdk-core/middleware';
|
|
6
5
|
import 'h3';
|
|
7
6
|
|
|
8
7
|
/**
|
package/dist/index.js
CHANGED
|
@@ -2,10 +2,11 @@ import "./chunk-ZNXAFGLP.js";
|
|
|
2
2
|
import {
|
|
3
3
|
createNextgenMiddleware,
|
|
4
4
|
getAuth
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-GQKD27DF.js";
|
|
6
6
|
|
|
7
7
|
// src/index.ts
|
|
8
8
|
import { ZitadelLogin, ZitadelLogout } from "@zitadel/components";
|
|
9
|
+
import { businessLocales } from "@zitadel/components";
|
|
9
10
|
|
|
10
11
|
// src/runtime/composables/useZitadelProject.ts
|
|
11
12
|
import { getZitadelConfig } from "@zitadel/api/config";
|
|
@@ -15,6 +16,7 @@ function useZitadelProject() {
|
|
|
15
16
|
export {
|
|
16
17
|
ZitadelLogin,
|
|
17
18
|
ZitadelLogout,
|
|
19
|
+
businessLocales,
|
|
18
20
|
createNextgenMiddleware,
|
|
19
21
|
getAuth,
|
|
20
22
|
useZitadelProject
|
package/dist/module.js
CHANGED
|
@@ -6,6 +6,27 @@ import {
|
|
|
6
6
|
addImportsDir,
|
|
7
7
|
createResolver
|
|
8
8
|
} from "@nuxt/kit";
|
|
9
|
+
import { existsSync, readFileSync } from "fs";
|
|
10
|
+
import { resolve as resolvePath } from "path";
|
|
11
|
+
function loadProjectSecret(rootDir) {
|
|
12
|
+
if (process.env.ZITADEL_PROJECT_SECRET) {
|
|
13
|
+
return process.env.ZITADEL_PROJECT_SECRET;
|
|
14
|
+
}
|
|
15
|
+
const path = resolvePath(rootDir, ".env.local");
|
|
16
|
+
if (!existsSync(path)) {
|
|
17
|
+
return void 0;
|
|
18
|
+
}
|
|
19
|
+
for (const line of readFileSync(path, "utf8").split(/\r?\n/)) {
|
|
20
|
+
const match = line.match(/^\s*(?:export\s+)?ZITADEL_PROJECT_SECRET\s*=\s*(.*)$/);
|
|
21
|
+
if (match && match[1] !== void 0) {
|
|
22
|
+
const raw = match[1].trim();
|
|
23
|
+
const quoted = raw.match(/^(['"])(.*)\1\s*(?:#.*)?$/);
|
|
24
|
+
const value = quoted ? quoted[2] : raw.replace(/\s+#.*$/, "").trim();
|
|
25
|
+
return value === "" ? void 0 : value;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return void 0;
|
|
29
|
+
}
|
|
9
30
|
var module_default = defineNuxtModule({
|
|
10
31
|
meta: {
|
|
11
32
|
name: "@zitadel/sdk-nuxt",
|
|
@@ -23,7 +44,12 @@ var module_default = defineNuxtModule({
|
|
|
23
44
|
url: options.url ?? "http://localhost:4000",
|
|
24
45
|
loginPath: options.loginPath ?? "/login",
|
|
25
46
|
protectedRoutes: options.protectedRoutes ?? [],
|
|
26
|
-
jwtKey: options.jwtKey
|
|
47
|
+
jwtKey: options.jwtKey,
|
|
48
|
+
// Server-only — never exposed to the client. Override at deploy time via
|
|
49
|
+
// `NUXT_NEXTGEN_PROJECT_SECRET`. Left undefined when the env var (and
|
|
50
|
+
// `.env.local`) provide no value, so the middleware surfaces a missing
|
|
51
|
+
// exchange bearer instead of silently sending an empty one.
|
|
52
|
+
projectSecret: loadProjectSecret(nuxt.options.rootDir)
|
|
27
53
|
};
|
|
28
54
|
nuxt.options.runtimeConfig.public.zitadelProxyPath = options.proxyPath ?? "/__nextgen";
|
|
29
55
|
nuxt.options.runtimeConfig.public.nextgenProxyPath = options.proxyPath ?? "/__nextgen";
|
package/dist/runtime/plugin.js
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
// src/runtime/plugin.ts
|
|
2
|
-
import {
|
|
3
|
-
defineNuxtPlugin,
|
|
4
|
-
useRequestEvent,
|
|
5
|
-
useRuntimeConfig,
|
|
6
|
-
useState
|
|
7
|
-
} from "#imports";
|
|
2
|
+
import { defineNuxtPlugin, useRequestEvent, useRuntimeConfig, useState } from "#imports";
|
|
8
3
|
import { configureZitadel } from "@zitadel/api/config";
|
|
9
4
|
var plugin_default = defineNuxtPlugin(() => {
|
|
10
5
|
const event = useRequestEvent();
|
|
@@ -16,8 +11,9 @@ var plugin_default = defineNuxtPlugin(() => {
|
|
|
16
11
|
isAuthenticated: true,
|
|
17
12
|
session: {
|
|
18
13
|
userId: auth.session.userId,
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
identifier: auth.session.identifier,
|
|
15
|
+
identifierProperty: auth.session.identifierProperty,
|
|
16
|
+
display: auth.session.display
|
|
21
17
|
}
|
|
22
18
|
} : { isAuthenticated: false, session: null };
|
|
23
19
|
useState("nextgen-auth", () => clientAuth);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { AuthResult, NextgenMiddlewareOptions } from '@zitadel/sdk-core/
|
|
1
|
+
import { AuthResult, NextgenMiddlewareOptions } from '@zitadel/sdk-core/middleware';
|
|
2
2
|
import { EventHandler, H3Event } from 'h3';
|
|
3
3
|
|
|
4
|
-
declare module
|
|
4
|
+
declare module "h3" {
|
|
5
5
|
interface H3EventContext {
|
|
6
6
|
nextgenAuth: AuthResult;
|
|
7
7
|
}
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -1,37 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export { AuthResult, AuthState, NextgenMiddlewareOptions, NextgenSession, UnauthState } from '@zitadel/sdk-core/types';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Re-exports shared SDK types from `@zitadel/sdk-core`.
|
|
6
|
-
*
|
|
7
|
-
* These types are defined once in sdk-core and shared by both sdk-next
|
|
8
|
-
* and sdk-nuxt.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* The client-safe session exposed to Vue components via {@link useAuth}.
|
|
13
|
-
* Identical to {@link NextgenSession} but omits `token` — the raw JWT must
|
|
14
|
-
* not be serialised into the Nuxt SSR payload where third-party scripts can
|
|
15
|
-
* read it.
|
|
16
|
-
*/
|
|
17
|
-
type ClientSession = {
|
|
18
|
-
/** The user's unique identifier (`sub` claim). */
|
|
19
|
-
userId: string;
|
|
20
|
-
/** The user's email address, or `null` if not present in the token. */
|
|
21
|
-
email: string | null;
|
|
22
|
-
/** The user's display name, or `null` if not present in the token. */
|
|
23
|
-
name: string | null;
|
|
24
|
-
};
|
|
25
|
-
/** Client-safe auth state when the user is signed in. */
|
|
26
|
-
type ClientAuthState = {
|
|
27
|
-
isAuthenticated: true;
|
|
28
|
-
session: ClientSession;
|
|
29
|
-
};
|
|
30
|
-
/**
|
|
31
|
-
* Union of all possible auth states returned by {@link useAuth}.
|
|
32
|
-
* Token is intentionally absent — use {@link getAuth} server-side when the
|
|
33
|
-
* raw JWT is needed.
|
|
34
|
-
*/
|
|
35
|
-
type ClientAuthResult = ClientAuthState | UnauthState;
|
|
36
|
-
|
|
37
|
-
export type { ClientAuthResult, ClientAuthState, ClientSession };
|
|
1
|
+
export { AuthResult, AuthState, ClientAuthResult, ClientAuthState, ClientSession, NextgenMiddlewareOptions, NextgenSession, UnauthState } from '@zitadel/sdk-core/middleware';
|
package/dist/server.d.ts
CHANGED
package/dist/server.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zitadel/sdk-nuxt",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Nuxt proxy middleware and helpers for
|
|
3
|
+
"version": "1.0.0-alpha.21",
|
|
4
|
+
"description": "Nuxt proxy middleware and helpers for the pre-release Zitadel preview.",
|
|
5
5
|
"homepage": "https://github.com/zitadel/nextgen/tree/main/packages/sdk-nuxt#readme",
|
|
6
6
|
"bugs": {
|
|
7
7
|
"url": "https://github.com/zitadel/nextgen/issues"
|
|
@@ -33,9 +33,9 @@
|
|
|
33
33
|
"access": "public"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@zitadel/
|
|
37
|
-
"@zitadel/
|
|
38
|
-
"@zitadel/
|
|
36
|
+
"@zitadel/api": "1.0.0-alpha.21",
|
|
37
|
+
"@zitadel/sdk-core": "1.0.0-alpha.21",
|
|
38
|
+
"@zitadel/components": "1.0.0-alpha.21"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"h3": ">=1",
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
"eslint-plugin-perfectionist": "^4.0.0",
|
|
54
54
|
"eslint-plugin-prettier": "^5.0.0",
|
|
55
55
|
"h3": "^1.15.3",
|
|
56
|
+
"nuxt": "^4.5.1",
|
|
56
57
|
"prettier": "^3.0.0",
|
|
57
58
|
"tsup": "^8.3.5",
|
|
58
59
|
"typescript": "^5.7.3",
|