@zitadel/sdk-next 0.1.0-alpha.17 → 0.1.0-alpha.18

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.
Files changed (45) hide show
  1. package/README.md +112 -7
  2. package/dist/auth.d.ts +54 -13
  3. package/dist/auth.d.ts.map +1 -0
  4. package/dist/auth.js +152 -7
  5. package/dist/client.d.ts +23 -2
  6. package/dist/client.d.ts.map +1 -0
  7. package/dist/client.js +21 -10
  8. package/dist/context.d.ts +21 -10
  9. package/dist/context.d.ts.map +1 -0
  10. package/dist/context.js +24 -8
  11. package/dist/index.d.ts +16 -9
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +13 -24
  14. package/dist/jsx.d.ts +5 -0
  15. package/dist/lib/jwt.d.ts +9 -0
  16. package/dist/lib/jwt.d.ts.map +1 -0
  17. package/dist/lib/jwt.js +7 -0
  18. package/dist/middleware.d.ts +9 -10
  19. package/dist/middleware.d.ts.map +1 -0
  20. package/dist/middleware.js +294 -9
  21. package/dist/provider.d.ts +52 -0
  22. package/dist/provider.d.ts.map +1 -0
  23. package/dist/provider.js +70 -0
  24. package/dist/react.d.ts +26 -0
  25. package/dist/react.d.ts.map +1 -0
  26. package/dist/react.js +24 -0
  27. package/dist/server.d.ts +12 -2
  28. package/dist/server.d.ts.map +1 -0
  29. package/dist/server.js +10 -7
  30. package/dist/session.d.ts +61 -0
  31. package/dist/session.d.ts.map +1 -0
  32. package/dist/session.js +115 -0
  33. package/dist/types.d.ts +8 -3
  34. package/dist/types.d.ts.map +1 -0
  35. package/dist/types.js +1 -1
  36. package/dist/useAuth.d.ts +17 -5
  37. package/dist/useAuth.d.ts.map +1 -0
  38. package/dist/useAuth.js +18 -7
  39. package/package.json +24 -9
  40. package/dist/chunk-2BFQLJQE.js +0 -27
  41. package/dist/chunk-6F4PWJZI.js +0 -0
  42. package/dist/chunk-7D5LORRL.js +0 -201
  43. package/dist/chunk-KHTLEMQO.js +0 -8
  44. package/dist/chunk-WZU5OYIF.js +0 -41
  45. package/dist/chunk-XTCHTAIQ.js +0 -12
package/README.md CHANGED
@@ -8,6 +8,23 @@ Next.js middleware and helpers for Nextgen Auth.
8
8
  pnpm add @zitadel/sdk-next
9
9
  ```
10
10
 
11
+ ## Entry points
12
+
13
+ | Import | Runs in | Provides |
14
+ | ------------------------------ | -------------------------------- | ------------------------------------------------ |
15
+ | `@zitadel/sdk-next/middleware` | Edge middleware | `nextgenMiddleware`, `createProxy` |
16
+ | `@zitadel/sdk-next/server` | Server Components, Route Handlers | `auth()`, `NextgenProvider` |
17
+ | `@zitadel/sdk-next/react` | Client Components | `useAuth()`, `AuthContextProvider` |
18
+ | `@zitadel/sdk-next/session` | Client Components | `getSession()` |
19
+ | `@zitadel/sdk-next/client` | Client boundary | Web-component registration, `configureZitadel()` |
20
+
21
+ The package root re-exports the server and client surfaces together for use
22
+ in server modules. Do not import the root from a `"use client"` module: it
23
+ pulls in the server-only `auth()`, which fails the build with an import trace
24
+ (exactly how depends on the bundler's tree shaking — the supported client
25
+ imports are `/react` and `/session`). `NextgenProvider` is itself server-only
26
+ because it accepts the token-bearing `auth()` result — see section 3.
27
+
11
28
  ## Setup
12
29
 
13
30
  ### 1. Middleware
@@ -40,7 +57,7 @@ The middleware runs on every matched route and does three things in one pass:
40
57
  ### 2. Reading auth in a Server Component
41
58
 
42
59
  ```ts
43
- import { auth } from "@zitadel/sdk-next";
60
+ import { auth } from "@zitadel/sdk-next/server";
44
61
 
45
62
  export default async function Page() {
46
63
  const session = await auth();
@@ -49,30 +66,65 @@ export default async function Page() {
49
66
  }
50
67
  ```
51
68
 
69
+ `auth()` reads the token the middleware tunnelled into the request headers
70
+ and **verifies it before trusting it** — JWTs cryptographically via JWKS,
71
+ opaque tokens against the backend's `GET /sessions/me` (which also supplies
72
+ the user's identity). A forged `x-nextgen-auth-token` header sent directly by
73
+ a client to a route outside the middleware `matcher` is rejected. Two things
74
+ follow:
75
+
76
+ - `auth()` only reports a session on routes the `matcher` covers — on other
77
+ routes the token never reaches it (see section 4 for chrome on public
78
+ pages).
79
+ - If the middleware runs with custom verification options (`audience`,
80
+ `allowedAlgorithms`, …), pass the same values to `auth()` so both layers
81
+ accept the same tokens.
82
+
83
+ `session.token` is the raw session token, available server-side for calling
84
+ upstream APIs. Never forward it into client components yourself —
85
+ `NextgenProvider` strips it for you (next section).
86
+
52
87
  ### 3. Reading auth in a Client Component
53
88
 
54
- Wrap your app in `NextgenProvider` (e.g. in your root layout):
89
+ Seed the client tree once in your root layout (a Server Component), then
90
+ read the state with `useAuth()` anywhere below it:
55
91
 
56
92
  ```tsx
57
- import { NextgenProvider } from '@zitadel/sdk-next';
93
+ import { auth, NextgenProvider } from '@zitadel/sdk-next/server';
58
94
 
59
95
  export default async function RootLayout({ children }) {
60
96
  const session = await auth();
61
97
  return (
62
98
  <html>
63
99
  <body>
64
- <NextgenProvider value={session}>{children}</NextgenProvider>
100
+ <NextgenProvider session={session}>{children}</NextgenProvider>
65
101
  </body>
66
102
  </html>
67
103
  );
68
104
  }
69
105
  ```
70
106
 
107
+ `NextgenProvider` converts the `auth()` result to the client-safe shape
108
+ **before** it crosses the server→client boundary: client components receive
109
+ `userId` / `email` / `name`, and the raw session token never enters the RSC
110
+ flight payload, where any script on the page could read it.
111
+
112
+ That strip only protects you while it runs on the server, which is why
113
+ `NextgenProvider` is server-only and **must not be re-exported through a
114
+ `"use client"` wrapper** (the common `providers.tsx` pattern): the wrapper
115
+ would become the client boundary, and its still-unstripped `session` prop —
116
+ token included — would serialise into the flight payload before the provider
117
+ ever ran. The `server-only` guard turns that wrapper into a build error
118
+ instead of a silent leak. To seed the context from client-side state (e.g. a
119
+ `getSession()` read), render `AuthContextProvider` from
120
+ `@zitadel/sdk-next/react` — it only accepts the token-less
121
+ `ClientAuthResult`.
122
+
71
123
  Then in any client component:
72
124
 
73
125
  ```tsx
74
126
  'use client';
75
- import { useAuth } from '@zitadel/sdk-next';
127
+ import { useAuth } from '@zitadel/sdk-next/react';
76
128
 
77
129
  export function UserBadge() {
78
130
  const auth = useAuth();
@@ -80,7 +132,58 @@ export function UserBadge() {
80
132
  }
81
133
  ```
82
134
 
83
- ### 4. Login page
135
+ `useAuth()` returns the same client-safe `ClientAuthResult` shape as
136
+ `getSession()` and sdk-nuxt's `useAuth()`. It reflects what the server knew
137
+ when the page rendered — which, like `auth()`, is only a live session on
138
+ routes the middleware `matcher` covers.
139
+
140
+ ### 4. Session state for your own UI (any page)
141
+
142
+ `auth()` only sees a session on routes the middleware `matcher` covers, and the
143
+ scaffolded matcher covers just the proxy path and the protected routes — so a
144
+ header on a public page would always look signed out. For your app's own chrome
145
+ (header navigation, account menus), read the session client-side with
146
+ `getSession()` from `@zitadel/sdk-next/session`. It fetches the same-origin
147
+ `{proxyPath}/sessions/me` — the same read the `<zitadel-session>` card performs —
148
+ so it works on every page and the answer is the server's:
149
+
150
+ ```tsx
151
+ 'use client';
152
+ import { useEffect, useState } from 'react';
153
+ import { getSession, type ClientAuthResult } from '@zitadel/sdk-next/session';
154
+
155
+ export function HeaderNav() {
156
+ // undefined = not yet known — render neutral chrome, not "Sign in".
157
+ const [auth, setAuth] = useState<ClientAuthResult>();
158
+ const [error, setError] = useState<Error>();
159
+ useEffect(() => {
160
+ getSession().then(setAuth, setError);
161
+ }, []);
162
+ if (error) return <span role="alert">Session unavailable</span>;
163
+ if (!auth) return null;
164
+ return auth.isAuthenticated ? (
165
+ <a href="/profile">{auth.session.name ?? auth.session.email ?? 'Account'}</a>
166
+ ) : (
167
+ <a href="/login">Sign in</a>
168
+ );
169
+ }
170
+ ```
171
+
172
+ A rejected `getSession()` means the state is *unknown* (broken proxy, network,
173
+ 5xx) — render a neutral or error state, never the signed-out CTAs.
174
+
175
+ A `200` with a non-empty `user_id` resolves to
176
+ `{ isAuthenticated: true, session: { userId, email, name } }` (client-safe —
177
+ no token); the canonical `401/auth.unauthorized`,
178
+ `404/sess.not_found`, and anonymous sessions resolve to signed out. The request
179
+ and response are both marked no-store. Any other response — including malformed
180
+ JSON or a framework's HTML 404 page from a misrouted proxy — throws so a broken
181
+ proxy doesn't silently render as signed out. Sign-in and sign-out navigate
182
+ (`post-sign-in-url` / `post-sign-out-url`), so chrome re-reads on the next page
183
+ load without extra wiring; to react in place, listen for the widgets'
184
+ `zitadel-signout` / `zitadel-flow-complete` events.
185
+
186
+ ### 5. Login page
84
187
 
85
188
  The `<zitadel-login>` web component (from `@zitadel/components`) must be rendered client-side only. Split it into a server wrapper and a client widget:
86
189
 
@@ -136,6 +239,7 @@ export function LoginWidget() {
136
239
  | `allowedTokenTypes` | `string[]` | `["JWT", "at+JWT"]` | Accepted `typ` header values (case-insensitive). Set to `[]` to disable this check |
137
240
  | `clockSkewMs` | `number` | `5000` | Clock skew tolerance in ms for `exp`, `nbf`, `iat` |
138
241
  | `jwksTimeoutMs` | `number` | `5000` | Timeout in ms for JWKS endpoint requests. Token is rejected if the fetch exceeds this window |
242
+ | `opaqueTokenTimeoutMs` | `number` | `5000` | Timeout in ms for opaque (non-JWT) session validation via `GET /sessions/me`. Also accepted by `auth()` |
139
243
  | `audience` | `string \| string[]` | not validated | Expected `aud` claim value(s). When omitted, audience is not checked |
140
244
 
141
245
  ## How JWT verification works
@@ -144,9 +248,10 @@ export function LoginWidget() {
144
248
  2. The JWT header is decoded to extract `kid` and `alg`
145
249
  3. Tokens with an `alg` not in `allowedAlgorithms` (`RS256`, `ES256` by default) are rejected immediately — no JWKS fetch
146
250
  4. Tokens with a `typ` not in `allowedTokenTypes` are rejected immediately
147
- 5. The public key is fetched from `{url}/oauth/v2/keys` (JWKS) using the Web Crypto API, with a 5 s timeout, and cached for 5 minutes per `kid`
251
+ 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`
148
252
  6. The signature is verified **before** any claim checks
149
253
  7. `iss` must be present and must equal `url` — tokens without an issuer are rejected
150
254
  8. `exp` must be present and must be in the future (with `clockSkewMs` tolerance) — tokens without an expiry are rejected
151
255
  9. `nbf` and `iat` are validated with `clockSkewMs` tolerance when present
152
256
  10. The `x-nextgen-auth-token` header is stripped from all proxied requests to prevent internal state leakage
257
+ 11. `auth()` re-applies the same verification to the tunnelled token in the server runtime — the header alone is never treated as proof of a session
package/dist/auth.d.ts CHANGED
@@ -1,17 +1,56 @@
1
- import { AuthResult } from '@zitadel/sdk-core/middleware';
2
-
1
+ import "server-only";
2
+ import type { AuthResult, NextgenMiddlewareOptions } from "./types.js";
3
+ /**
4
+ * Options for {@link auth}.
5
+ *
6
+ * These mirror the token-verification subset of the middleware options. When
7
+ * the middleware runs with custom verification settings (a non-default
8
+ * `audience`, `allowedAlgorithms`, …), pass the same values here — otherwise
9
+ * a token the middleware accepted can fail re-verification in `auth()` and
10
+ * render as signed out.
11
+ */
12
+ export type AuthOptions = Pick<NextgenMiddlewareOptions, "url" | "allowedAlgorithms" | "clockSkewMs" | "audience" | "allowedTokenTypes" | "jwksTimeoutMs" | "opaqueTokenTimeoutMs">;
3
13
  /**
4
14
  * Reads the auth state in a React Server Component or Next.js Route Handler.
5
15
  *
6
- * - **JWT tokens** are decoded locally (no backend round-trip).
7
- * - **Opaque encrypted tokens** have already been validated by the
8
- * middleware via `GET /sessions/me`. If the `x-nextgen-auth-token`
9
- * header is set, the session is authentic. Session details (email,
10
- * name) are not available server-side for opaque tokens use the
11
- * `/__nextgen/sessions/me` proxy from a client component to fetch them.
16
+ * The session token arrives on the `x-nextgen-auth-token` request header,
17
+ * tunnelled there by the middleware and `auth()` **verifies it before
18
+ * trusting it**:
19
+ *
20
+ * - **JWT tokens** are verified cryptographically (signature via JWKS,
21
+ * issuer, expiry, algorithm and type allow-lists) using the same rules and
22
+ * defaults as the middleware. The JWKS is cached in-process, so this does
23
+ * not add a backend round-trip after the first call.
24
+ * - **Opaque encrypted tokens** are validated against the backend's
25
+ * `GET /sessions/me`, which also supplies the user's identity (`userId`,
26
+ * `email`, `name`). The lookup is deduplicated per render pass via React
27
+ * `cache()`.
28
+ *
29
+ * The header alone is never proof of anything: on routes the middleware
30
+ * `matcher` does not cover, the middleware cannot neutralise a forged
31
+ * client-supplied header, so `auth()` re-verifies every value it reads.
32
+ * A header value that fails verification is treated as signed out.
33
+ *
34
+ * **Matcher precondition (read this):** the middleware only tunnels the
35
+ * session token on routes covered by its `matcher`. On uncovered routes the
36
+ * cookie never reaches `auth()`, so `auth()` reports signed out even when a
37
+ * live session exists. Either extend the `matcher` to every route that calls
38
+ * `auth()`, or — for app chrome like headers and account menus — read the
39
+ * session client-side with `getSession()` from `@zitadel/sdk-next/session`,
40
+ * which works on any page.
41
+ *
42
+ * The backend URL comes from `options.url`, falling back to the same
43
+ * `ZITADEL_URL` environment variable the middleware uses. If the middleware
44
+ * runs with custom verification options (`audience`, `allowedAlgorithms`, …),
45
+ * pass the same values here; see {@link AuthOptions}.
46
+ *
47
+ * This module is server-only: importing it (or the package root) from a
48
+ * client component fails at build time. Client components read auth state
49
+ * from `@zitadel/sdk-next/react` (`useAuth()`) or
50
+ * `@zitadel/sdk-next/session` (`getSession()`).
12
51
  *
13
52
  * ```ts
14
- * import { auth } from "@zitadel/sdk-next";
53
+ * import { auth } from "@zitadel/sdk-next/server";
15
54
  *
16
55
  * export default async function Page() {
17
56
  * const session = await auth();
@@ -20,8 +59,10 @@ import { AuthResult } from '@zitadel/sdk-core/middleware';
20
59
  * }
21
60
  * ```
22
61
  *
23
- * @returns The current {@link AuthResult}.
62
+ * @param options - Optional verification settings; see {@link AuthOptions}.
63
+ * @returns The current {@link AuthResult}. `session.token` is the raw session
64
+ * token for calling upstream APIs server-side — never forward it into
65
+ * client components (the `NextgenProvider` strips it for you).
24
66
  */
25
- declare function auth(): Promise<AuthResult>;
26
-
27
- export { auth };
67
+ export declare function auth(options?: AuthOptions): Promise<AuthResult>;
68
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAC;AAOrB,OAAO,KAAK,EAAE,UAAU,EAAiB,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAItF;;;;;;;;GAQG;AACH,MAAM,MAAM,WAAW,GAAG,IAAI,CAC5B,wBAAwB,EACtB,KAAK,GACL,mBAAmB,GACnB,aAAa,GACb,UAAU,GACV,mBAAmB,GACnB,eAAe,GACf,sBAAsB,CACzB,CAAC;AA8DF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,wBAAsB,IAAI,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,CA6DzE"}
package/dist/auth.js CHANGED
@@ -1,7 +1,152 @@
1
- import {
2
- auth
3
- } from "./chunk-WZU5OYIF.js";
4
- import "./chunk-KHTLEMQO.js";
5
- export {
6
- auth
7
- };
1
+ import "server-only";
2
+ import { headers } from "next/headers";
3
+ import { cache } from "react";
4
+ import { isJwtShaped, verifyJwt } from "./lib/jwt.js";
5
+ /**
6
+ * Validates an opaque (non-JWT) session token against the backend's
7
+ * `GET /sessions/me` and returns the client-safe identity, or `null` when the
8
+ * backend does not confirm a signed-in user.
9
+ *
10
+ * Wrapped in React's `cache()` so that many components calling `auth()` in
11
+ * the same render pass share a single backend round-trip. Arguments are
12
+ * primitives on purpose — `cache()` memoises by argument identity.
13
+ *
14
+ * Fail-closed: network errors, timeouts, and unexpected statuses all resolve
15
+ * to `null` (signed out). Unexpected failures are logged so a broken proxy or
16
+ * unreachable backend is distinguishable from a genuinely missing session.
17
+ */
18
+ const validateOpaqueSession = cache(async (token, issuerUrl, timeoutMs) => {
19
+ try {
20
+ const res = await fetch(`${issuerUrl}/sessions/me`, {
21
+ method: "GET",
22
+ headers: { accept: "application/json", cookie: `__nextgen_session=${token}` },
23
+ signal: AbortSignal.timeout(timeoutMs),
24
+ });
25
+ // 401 = no/invalid session token, 404 = session gone (revoked/expired):
26
+ // both are the server's definitive "not signed in".
27
+ if (res.status === 401 || res.status === 404) {
28
+ return null;
29
+ }
30
+ if (!res.ok) {
31
+ console.warn(`[nextgen] auth(): session validation failed with HTTP ${res.status} from ` +
32
+ `${issuerUrl}/sessions/me — treating as signed out. If this persists, the ` +
33
+ `backend URL is likely misconfigured (ZITADEL_URL or the \`url\` option).`);
34
+ return null;
35
+ }
36
+ const session = (await res.json());
37
+ // An anonymous session (no verified user factor yet) has no user_id —
38
+ // for server-rendered UI that is "not signed in".
39
+ if (!session.user_id) {
40
+ return null;
41
+ }
42
+ return {
43
+ userId: session.user_id,
44
+ email: session.email ?? null,
45
+ name: session.name ?? null,
46
+ };
47
+ }
48
+ catch {
49
+ console.warn(`[nextgen] auth(): could not reach ${issuerUrl}/sessions/me to validate the ` +
50
+ `session token — treating as signed out.`);
51
+ return null;
52
+ }
53
+ });
54
+ /**
55
+ * Reads the auth state in a React Server Component or Next.js Route Handler.
56
+ *
57
+ * The session token arrives on the `x-nextgen-auth-token` request header,
58
+ * tunnelled there by the middleware — and `auth()` **verifies it before
59
+ * trusting it**:
60
+ *
61
+ * - **JWT tokens** are verified cryptographically (signature via JWKS,
62
+ * issuer, expiry, algorithm and type allow-lists) using the same rules and
63
+ * defaults as the middleware. The JWKS is cached in-process, so this does
64
+ * not add a backend round-trip after the first call.
65
+ * - **Opaque encrypted tokens** are validated against the backend's
66
+ * `GET /sessions/me`, which also supplies the user's identity (`userId`,
67
+ * `email`, `name`). The lookup is deduplicated per render pass via React
68
+ * `cache()`.
69
+ *
70
+ * The header alone is never proof of anything: on routes the middleware
71
+ * `matcher` does not cover, the middleware cannot neutralise a forged
72
+ * client-supplied header, so `auth()` re-verifies every value it reads.
73
+ * A header value that fails verification is treated as signed out.
74
+ *
75
+ * **Matcher precondition (read this):** the middleware only tunnels the
76
+ * session token on routes covered by its `matcher`. On uncovered routes the
77
+ * cookie never reaches `auth()`, so `auth()` reports signed out even when a
78
+ * live session exists. Either extend the `matcher` to every route that calls
79
+ * `auth()`, or — for app chrome like headers and account menus — read the
80
+ * session client-side with `getSession()` from `@zitadel/sdk-next/session`,
81
+ * which works on any page.
82
+ *
83
+ * The backend URL comes from `options.url`, falling back to the same
84
+ * `ZITADEL_URL` environment variable the middleware uses. If the middleware
85
+ * runs with custom verification options (`audience`, `allowedAlgorithms`, …),
86
+ * pass the same values here; see {@link AuthOptions}.
87
+ *
88
+ * This module is server-only: importing it (or the package root) from a
89
+ * client component fails at build time. Client components read auth state
90
+ * from `@zitadel/sdk-next/react` (`useAuth()`) or
91
+ * `@zitadel/sdk-next/session` (`getSession()`).
92
+ *
93
+ * ```ts
94
+ * import { auth } from "@zitadel/sdk-next/server";
95
+ *
96
+ * export default async function Page() {
97
+ * const session = await auth();
98
+ * if (!session.isAuthenticated) return <p>Not signed in</p>;
99
+ * return <p>Hello {session.session.userId}</p>;
100
+ * }
101
+ * ```
102
+ *
103
+ * @param options - Optional verification settings; see {@link AuthOptions}.
104
+ * @returns The current {@link AuthResult}. `session.token` is the raw session
105
+ * token for calling upstream APIs server-side — never forward it into
106
+ * client components (the `NextgenProvider` strips it for you).
107
+ */
108
+ export async function auth(options = {}) {
109
+ const headerStore = await headers();
110
+ const token = headerStore.get("x-nextgen-auth-token");
111
+ if (!token) {
112
+ return { isAuthenticated: false, session: null };
113
+ }
114
+ const { url = process.env.ZITADEL_URL ?? "http://localhost:8080", allowedAlgorithms = ["RS256", "ES256"], clockSkewMs = 5000, audience, allowedTokenTypes = ["JWT", "at+JWT"], jwksTimeoutMs, opaqueTokenTimeoutMs = 5000, } = options;
115
+ if (isJwtShaped(token)) {
116
+ const payload = await verifyJwt(token, {
117
+ issuerUrl: url,
118
+ allowedAlgorithms,
119
+ clockSkewMs,
120
+ audience,
121
+ allowedTokenTypes,
122
+ jwksTimeoutMs,
123
+ });
124
+ if (payload?.sub) {
125
+ return {
126
+ isAuthenticated: true,
127
+ session: {
128
+ userId: payload.sub,
129
+ email: payload.email ?? null,
130
+ name: payload.name ?? null,
131
+ token,
132
+ },
133
+ };
134
+ }
135
+ // A middleware-tunnelled JWT always verifies (the middleware applied the
136
+ // same checks moments earlier). Reaching this branch means the header was
137
+ // NOT vetted by the middleware — a route outside the `matcher` received a
138
+ // client-forged header — or the JWKS endpoint is unreachable from this
139
+ // runtime, or auth() runs with verification options that diverge from the
140
+ // middleware's.
141
+ console.warn("[nextgen] auth(): rejected an x-nextgen-auth-token header that failed JWT " +
142
+ "verification. If this route is not covered by the middleware matcher, this was " +
143
+ "a forged client header; otherwise check that auth() and the middleware use the " +
144
+ `same verification options and that the JWKS endpoint at ${url}/auth/keys is reachable.`);
145
+ return { isAuthenticated: false, session: null };
146
+ }
147
+ const session = await validateOpaqueSession(token, url, opaqueTokenTimeoutMs);
148
+ if (session) {
149
+ return { isAuthenticated: true, session: { ...session, token } };
150
+ }
151
+ return { isAuthenticated: false, session: null };
152
+ }
package/dist/client.d.ts CHANGED
@@ -1,2 +1,23 @@
1
- export { ZitadelLogin, ZitadelLogout, ZitadelSession } from '@zitadel/components';
2
- export { ZitadelConfig, ZitadelProject, configureZitadel, getApi } from '@zitadel/api/config';
1
+ /**
2
+ * Re-exports the `<zitadel-login>` and `<zitadel-logout>` Lit web components
3
+ * for use in Next.js apps.
4
+ *
5
+ * Import this inside a `"use client"` boundary (e.g. a dynamic import
6
+ * with `{ ssr: false }`) to register the custom elements with the
7
+ * browser's global registry:
8
+ *
9
+ * ```ts
10
+ * await import("@zitadel/sdk-next/client");
11
+ * ```
12
+ *
13
+ * SDK configuration is done via `configureZitadel()`, re-exported here so
14
+ * a consuming app that only declares `@zitadel/sdk-next` as a direct
15
+ * dependency can configure the SDK without reaching into
16
+ * `@zitadel/api/config` (which strict package managers would not
17
+ * resolve). Call it inside the same `"use client"` boundary before the
18
+ * components mount.
19
+ */
20
+ export { ZitadelLogin, ZitadelLogout, ZitadelSession, businessLocales } from "@zitadel/components";
21
+ export { configureZitadel, getApi } from "@zitadel/api/config";
22
+ export type { ZitadelConfig, ZitadelProject } from "@zitadel/api/config";
23
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACnG,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC/D,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC"}
package/dist/client.js CHANGED
@@ -1,10 +1,21 @@
1
- // src/client.ts
2
- import { ZitadelLogin, ZitadelLogout, ZitadelSession } from "@zitadel/components";
3
- import { configureZitadel, getApi } from "@zitadel/api/config";
4
- export {
5
- ZitadelLogin,
6
- ZitadelLogout,
7
- ZitadelSession,
8
- configureZitadel,
9
- getApi
10
- };
1
+ /**
2
+ * Re-exports the `<zitadel-login>` and `<zitadel-logout>` Lit web components
3
+ * for use in Next.js apps.
4
+ *
5
+ * Import this inside a `"use client"` boundary (e.g. a dynamic import
6
+ * with `{ ssr: false }`) to register the custom elements with the
7
+ * browser's global registry:
8
+ *
9
+ * ```ts
10
+ * await import("@zitadel/sdk-next/client");
11
+ * ```
12
+ *
13
+ * SDK configuration is done via `configureZitadel()`, re-exported here so
14
+ * a consuming app that only declares `@zitadel/sdk-next` as a direct
15
+ * dependency can configure the SDK without reaching into
16
+ * `@zitadel/api/config` (which strict package managers would not
17
+ * resolve). Call it inside the same `"use client"` boundary before the
18
+ * components mount.
19
+ */
20
+ export { ZitadelLogin, ZitadelLogout, ZitadelSession, businessLocales } from "@zitadel/components";
21
+ export { configureZitadel, getApi } from "@zitadel/api/config";
package/dist/context.d.ts CHANGED
@@ -1,11 +1,22 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ReactNode } from 'react';
3
- import { AuthResult, NextgenSession } from '@zitadel/sdk-core/middleware';
4
-
5
- declare function NextgenProvider({ session, children, }: {
6
- session: AuthResult | NextgenSession | null;
1
+ import { type ReactNode } from "react";
2
+ import type { ClientAuthResult } from "./types.js";
3
+ /**
4
+ * Client-side context carrier. In the standard server-seeded setup, render
5
+ * {@link NextgenProvider} from `@zitadel/sdk-next/server` instead — it
6
+ * normalises the server's `auth()` result to the client-safe shape (dropping
7
+ * the raw session token) *before* the value crosses the server→client
8
+ * component boundary, and its `server-only` guard keeps it out of client
9
+ * wrappers where that strip would come too late.
10
+ *
11
+ * Render this component directly only from client code that already holds a
12
+ * client-safe value — e.g. seeding from a `getSession()` read.
13
+ *
14
+ * The `value` prop is deliberately typed as {@link ClientAuthResult}: the
15
+ * raw session token must never enter client-side state.
16
+ */
17
+ export declare function AuthContextProvider({ value, children, }: {
18
+ value: ClientAuthResult;
7
19
  children: ReactNode;
8
- }): react_jsx_runtime.JSX.Element;
9
- declare function useAuthContext(): AuthResult;
10
-
11
- export { NextgenProvider, useAuthContext };
20
+ }): import("react/jsx-runtime").JSX.Element;
21
+ export declare function useAuthContext(): ClientAuthResult;
22
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAElE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAMnD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,KAAK,EACL,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,gBAAgB,CAAC;IACxB,QAAQ,EAAE,SAAS,CAAC;CACrB,2CAEA;AAED,wBAAgB,cAAc,IAAI,gBAAgB,CAEjD"}
package/dist/context.js CHANGED
@@ -1,9 +1,25 @@
1
1
  "use client";
2
- import {
3
- NextgenProvider,
4
- useAuthContext
5
- } from "./chunk-2BFQLJQE.js";
6
- export {
7
- NextgenProvider,
8
- useAuthContext
9
- };
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { createContext, useContext } from "react";
4
+ const defaultValue = { isAuthenticated: false, session: null };
5
+ const NextgenAuthContext = createContext(defaultValue);
6
+ /**
7
+ * Client-side context carrier. In the standard server-seeded setup, render
8
+ * {@link NextgenProvider} from `@zitadel/sdk-next/server` instead — it
9
+ * normalises the server's `auth()` result to the client-safe shape (dropping
10
+ * the raw session token) *before* the value crosses the server→client
11
+ * component boundary, and its `server-only` guard keeps it out of client
12
+ * wrappers where that strip would come too late.
13
+ *
14
+ * Render this component directly only from client code that already holds a
15
+ * client-safe value — e.g. seeding from a `getSession()` read.
16
+ *
17
+ * The `value` prop is deliberately typed as {@link ClientAuthResult}: the
18
+ * raw session token must never enter client-side state.
19
+ */
20
+ export function AuthContextProvider({ value, children, }) {
21
+ return _jsx(NextgenAuthContext.Provider, { value: value, children: children });
22
+ }
23
+ export function useAuthContext() {
24
+ return useContext(NextgenAuthContext);
25
+ }
package/dist/index.d.ts CHANGED
@@ -1,9 +1,16 @@
1
- export { AuthResult, AuthState, NextgenMiddlewareOptions, NextgenSession, UnauthState } from '@zitadel/sdk-core/middleware';
2
- export { ProxyHandler, ProxyOptions, createProxy, nextgenMiddleware } from './middleware.js';
3
- export { auth } from './auth.js';
4
- export { NextgenProvider, useAuthContext } from './context.js';
5
- export { useAuth } from './useAuth.js';
6
- import '@zitadel/api/config';
7
- import 'next/server';
8
- import 'react/jsx-runtime';
9
- import 'react';
1
+ /**
2
+ * Package root for **Server Components and server modules only**: it
3
+ * includes the server-only `auth()`, so importing it from a `"use client"`
4
+ * module fails at build time. Client components import from
5
+ * `@zitadel/sdk-next/react` (provider + hooks) or
6
+ * `@zitadel/sdk-next/session` (`getSession()`) instead.
7
+ */
8
+ export * from "./types.js";
9
+ export { nextgenMiddleware, createProxy } from "./middleware.js";
10
+ export type { ProxyOptions, ProxyHandler } from "./middleware.js";
11
+ export { auth } from "./auth.js";
12
+ export type { AuthOptions } from "./auth.js";
13
+ export { NextgenProvider } from "./provider.js";
14
+ export { AuthContextProvider, useAuthContext } from "./context.js";
15
+ export { useAuth } from "./useAuth.js";
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACjE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js CHANGED
@@ -1,24 +1,13 @@
1
- import {
2
- createProxy,
3
- nextgenMiddleware
4
- } from "./chunk-7D5LORRL.js";
5
- import {
6
- auth
7
- } from "./chunk-WZU5OYIF.js";
8
- import "./chunk-KHTLEMQO.js";
9
- import "./chunk-6F4PWJZI.js";
10
- import {
11
- useAuth
12
- } from "./chunk-XTCHTAIQ.js";
13
- import {
14
- NextgenProvider,
15
- useAuthContext
16
- } from "./chunk-2BFQLJQE.js";
17
- export {
18
- NextgenProvider,
19
- auth,
20
- createProxy,
21
- nextgenMiddleware,
22
- useAuth,
23
- useAuthContext
24
- };
1
+ /**
2
+ * Package root — for **Server Components and server modules only**: it
3
+ * includes the server-only `auth()`, so importing it from a `"use client"`
4
+ * module fails at build time. Client components import from
5
+ * `@zitadel/sdk-next/react` (provider + hooks) or
6
+ * `@zitadel/sdk-next/session` (`getSession()`) instead.
7
+ */
8
+ export * from "./types.js";
9
+ export { nextgenMiddleware, createProxy } from "./middleware.js";
10
+ export { auth } from "./auth.js";
11
+ export { NextgenProvider } from "./provider.js";
12
+ export { AuthContextProvider, useAuthContext } from "./context.js";
13
+ export { useAuth } from "./useAuth.js";
package/dist/jsx.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ // Types-only shim: scaffolded apps depend on @zitadel/sdk-next, not
2
+ // @zitadel/components, so the React JSX declarations for the <zitadel-*>
3
+ // elements are re-exposed here as `@zitadel/sdk-next/jsx`. Copied verbatim
4
+ // into dist/ by the build script.
5
+ /// <reference types="@zitadel/components/jsx" />
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Re-exports shared JWT verification from `@zitadel/sdk-core`.
3
+ *
4
+ * The JWT module is runtime-agnostic (uses `atob` which is available in both
5
+ * Edge and Node.js 16+) and is defined once in sdk-core.
6
+ */
7
+ export { JWKS_TTL_MS, base64UrlDecode, decodeJwt, isJwtShaped, verifyJwt, } from "@zitadel/sdk-core/jwt";
8
+ export type { JwtPayload, JwtHeader, DecodedJwt, VerifyJwtOptions } from "@zitadel/sdk-core/jwt";
9
+ //# sourceMappingURL=jwt.d.ts.map