@zitadel/sdk-next 0.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ZITADEL
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,152 @@
1
+ # @zitadel/sdk-next
2
+
3
+ Next.js middleware and helpers for Nextgen Auth.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @zitadel/sdk-next
9
+ ```
10
+
11
+ ## Setup
12
+
13
+ ### 1. Middleware
14
+
15
+ Create `src/proxy.ts` at the root of your Next.js app:
16
+
17
+ ```ts
18
+ import { nextgenMiddleware } from '@zitadel/sdk-next/middleware';
19
+ import type { NextRequest } from 'next/server';
20
+
21
+ export function proxy(req: NextRequest) {
22
+ return nextgenMiddleware(req, {
23
+ url: process.env.ZITADEL_URL,
24
+ protectedRoutes: ['/admin', '/dashboard*'],
25
+ loginPath: '/login',
26
+ });
27
+ }
28
+
29
+ export const config = {
30
+ matcher: ['/__nextgen/:path*', '/admin', '/login'],
31
+ };
32
+ ```
33
+
34
+ The middleware runs on every matched route and does three things in one pass:
35
+
36
+ 1. **Proxies** `/__nextgen/*` requests to the auth backend
37
+ 2. **Verifies** the session JWT via JWKS using the Web Crypto API
38
+ 3. **Redirects** unauthenticated requests to `loginPath` for protected routes
39
+
40
+ ### 2. Reading auth in a Server Component
41
+
42
+ ```ts
43
+ import { auth } from "@zitadel/sdk-next";
44
+
45
+ export default async function Page() {
46
+ const session = await auth();
47
+ if (!session.isAuthenticated) return <p>Not signed in</p>;
48
+ return <p>Hello {session.session.email}</p>;
49
+ }
50
+ ```
51
+
52
+ ### 3. Reading auth in a Client Component
53
+
54
+ Wrap your app in `NextgenProvider` (e.g. in your root layout):
55
+
56
+ ```tsx
57
+ import { NextgenProvider } from '@zitadel/sdk-next';
58
+
59
+ export default async function RootLayout({ children }) {
60
+ const session = await auth();
61
+ return (
62
+ <html>
63
+ <body>
64
+ <NextgenProvider value={session}>{children}</NextgenProvider>
65
+ </body>
66
+ </html>
67
+ );
68
+ }
69
+ ```
70
+
71
+ Then in any client component:
72
+
73
+ ```tsx
74
+ 'use client';
75
+ import { useAuth } from '@zitadel/sdk-next';
76
+
77
+ export function UserBadge() {
78
+ const auth = useAuth();
79
+ return <span>{auth.isAuthenticated ? auth.session.email : 'Guest'}</span>;
80
+ }
81
+ ```
82
+
83
+ ### 4. Login page
84
+
85
+ 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
+
87
+ ```tsx
88
+ // app/login/page.tsx (server)
89
+ import { auth } from '@zitadel/sdk-next';
90
+ import { redirect } from 'next/navigation';
91
+ import { LoginWidget } from './widget';
92
+
93
+ export default async function LoginPage() {
94
+ const session = await auth();
95
+ if (session.isAuthenticated) redirect('/admin');
96
+ return <LoginWidget />;
97
+ }
98
+ ```
99
+
100
+ ```tsx
101
+ // app/login/widget.tsx (client)
102
+ 'use client';
103
+ import dynamic from 'next/dynamic';
104
+
105
+ const ZitadelLogin = dynamic(
106
+ async () => {
107
+ await import('@zitadel/components');
108
+ return function ZitadelLoginElement() {
109
+ return (
110
+ <zitadel-login
111
+ api-base="/__nextgen"
112
+ project-id="demo"
113
+ post-sign-in-url="/admin"
114
+ />
115
+ );
116
+ };
117
+ },
118
+ { ssr: false },
119
+ );
120
+
121
+ export function LoginWidget() {
122
+ return <ZitadelLogin />;
123
+ }
124
+ ```
125
+
126
+ ## Middleware options
127
+
128
+ | Option | Type | Default | Description |
129
+ | ------------------- | -------------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------------------- |
130
+ | `url` | `string` | `ZITADEL_URL` env | Full URL of the Zitadel auth backend |
131
+ | `proxyPath` | `string` | `"/__nextgen"` | Path prefix proxied to the auth backend |
132
+ | `protectedRoutes` | `string[]` | `[]` | Paths requiring a valid session. Trailing `*` matches sub-paths |
133
+ | `ignoredRoutes` | `string[]` | `[]` | Paths skipped entirely — no JWT check, no tunnelling. Useful for webhooks or health checks. Trailing `*` matches sub-paths |
134
+ | `loginPath` | `string` | `"/login"` | Where to redirect unauthenticated users |
135
+ | `allowedAlgorithms` | `string[]` | `["RS256", "ES256"]` | JWT `alg` values to accept. Tokens with any other algorithm are rejected before JWKS is fetched |
136
+ | `allowedTokenTypes` | `string[]` | `["JWT", "at+JWT"]` | Accepted `typ` header values (case-insensitive). Set to `[]` to disable this check |
137
+ | `clockSkewMs` | `number` | `5000` | Clock skew tolerance in ms for `exp`, `nbf`, `iat` |
138
+ | `jwksTimeoutMs` | `number` | `5000` | Timeout in ms for JWKS endpoint requests. Token is rejected if the fetch exceeds this window |
139
+ | `audience` | `string \| string[]` | not validated | Expected `aud` claim value(s). When omitted, audience is not checked |
140
+
141
+ ## How JWT verification works
142
+
143
+ 1. Bearer token from `Authorization` header is checked first; `__nextgen_session` cookie is the fallback
144
+ 2. The JWT header is decoded to extract `kid` and `alg`
145
+ 3. Tokens with an `alg` not in `allowedAlgorithms` (`RS256`, `ES256` by default) are rejected immediately — no JWKS fetch
146
+ 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`
148
+ 6. The signature is verified **before** any claim checks
149
+ 7. `iss` must be present and must equal `url` — tokens without an issuer are rejected
150
+ 8. `exp` must be present and must be in the future (with `clockSkewMs` tolerance) — tokens without an expiry are rejected
151
+ 9. `nbf` and `iat` are validated with `clockSkewMs` tolerance when present
152
+ 10. The `x-nextgen-auth-token` header is stripped from all proxied requests to prevent internal state leakage
package/dist/auth.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ import { AuthResult } from '@zitadel/sdk-core/types';
2
+
3
+ /**
4
+ * Reads the auth state in a React Server Component or Next.js Route Handler.
5
+ *
6
+ * The middleware verifies the JWT and tunnels it to the RSC runtime via
7
+ * `x-nextgen-auth-token`. This function decodes the tunnelled token without
8
+ * re-verifying the signature — verification has already been done by the
9
+ * middleware on every request.
10
+ *
11
+ * ```ts
12
+ * import { auth } from "@zitadel/sdk-next";
13
+ *
14
+ * export default async function Page() {
15
+ * const session = await auth();
16
+ * if (!session.isAuthenticated) return <p>Not signed in</p>;
17
+ * return <p>Hello {session.session.email}</p>;
18
+ * }
19
+ * ```
20
+ *
21
+ * @returns The current {@link AuthResult}.
22
+ */
23
+ declare function auth(): Promise<AuthResult>;
24
+
25
+ export { auth };
package/dist/auth.js ADDED
@@ -0,0 +1,7 @@
1
+ import {
2
+ auth
3
+ } from "./chunk-EAUJMJ45.js";
4
+ import "./chunk-5P5THDJF.js";
5
+ export {
6
+ auth
7
+ };
@@ -0,0 +1,27 @@
1
+ // src/context.tsx
2
+ import { createContext, useContext } from "react";
3
+ import { jsx } from "react/jsx-runtime";
4
+ var defaultValue = { isAuthenticated: false, session: null };
5
+ var NextgenAuthContext = createContext(defaultValue);
6
+ function NextgenProvider({
7
+ session,
8
+ children
9
+ }) {
10
+ let value;
11
+ if (!session) {
12
+ value = { isAuthenticated: false, session: null };
13
+ } else if ("isAuthenticated" in session) {
14
+ value = session;
15
+ } else {
16
+ value = { isAuthenticated: true, session };
17
+ }
18
+ return /* @__PURE__ */ jsx(NextgenAuthContext.Provider, { value, children });
19
+ }
20
+ function useAuthContext() {
21
+ return useContext(NextgenAuthContext);
22
+ }
23
+
24
+ export {
25
+ NextgenProvider,
26
+ useAuthContext
27
+ };
@@ -0,0 +1,12 @@
1
+ // src/lib/jwt.ts
2
+ import {
3
+ JWKS_TTL_MS,
4
+ base64UrlDecode,
5
+ decodeJwt,
6
+ verifyJwt
7
+ } from "@zitadel/sdk-core/jwt";
8
+
9
+ export {
10
+ decodeJwt,
11
+ verifyJwt
12
+ };
File without changes
@@ -0,0 +1,34 @@
1
+ import {
2
+ decodeJwt
3
+ } from "./chunk-5P5THDJF.js";
4
+
5
+ // src/auth.ts
6
+ import { headers } from "next/headers";
7
+ async function auth() {
8
+ try {
9
+ const headerStore = await headers();
10
+ const token = headerStore.get("x-nextgen-auth-token");
11
+ if (!token) {
12
+ return { isAuthenticated: false, session: null };
13
+ }
14
+ const { payload } = decodeJwt(token);
15
+ if (!payload.sub) {
16
+ return { isAuthenticated: false, session: null };
17
+ }
18
+ return {
19
+ isAuthenticated: true,
20
+ session: {
21
+ userId: payload.sub,
22
+ email: payload.email ?? null,
23
+ name: payload.name ?? null,
24
+ token
25
+ }
26
+ };
27
+ } catch {
28
+ return { isAuthenticated: false, session: null };
29
+ }
30
+ }
31
+
32
+ export {
33
+ auth
34
+ };
@@ -0,0 +1,177 @@
1
+ import {
2
+ verifyJwt
3
+ } from "./chunk-5P5THDJF.js";
4
+
5
+ // src/middleware.ts
6
+ import {
7
+ HOP_BY_HOP,
8
+ INTERNAL_HEADERS,
9
+ filterResponseHeaders,
10
+ matchesRoutes
11
+ } from "@zitadel/sdk-core/middleware";
12
+ import { NextResponse } from "next/server";
13
+ function tunnelHeaders(req, extra) {
14
+ const headers = new Headers(req.headers);
15
+ headers.delete("x-middleware-override-headers");
16
+ const injectedNames = [];
17
+ for (const [name, value] of Object.entries(extra)) {
18
+ headers.set(name, value);
19
+ headers.set(`x-middleware-request-${name}`, value);
20
+ injectedNames.push(name);
21
+ }
22
+ headers.set("x-middleware-override-headers", injectedNames.join(","));
23
+ return headers;
24
+ }
25
+ async function nextgenMiddleware(req, options = {}) {
26
+ const {
27
+ url = process.env.ZITADEL_URL ?? "http://localhost:8080",
28
+ proxyPath = "/__nextgen",
29
+ protectedRoutes = [],
30
+ ignoredRoutes = [],
31
+ loginPath = "/login",
32
+ allowedAlgorithms = ["RS256", "ES256"],
33
+ clockSkewMs = 5e3,
34
+ audience,
35
+ allowedTokenTypes = ["JWT", "at+JWT"],
36
+ jwksTimeoutMs,
37
+ proxyTimeoutMs = 5e3,
38
+ onExchangeResponse
39
+ } = options;
40
+ if (!loginPath.startsWith("/") || loginPath.startsWith("//")) {
41
+ throw new Error(
42
+ `[nextgen] loginPath must be a relative path starting with a single "/". Received: "${loginPath}". Using an absolute or protocol-relative URL would allow open-redirect attacks.`
43
+ );
44
+ }
45
+ const { pathname } = new URL(req.url);
46
+ if (matchesRoutes(pathname, ignoredRoutes)) {
47
+ const headers = tunnelHeaders(req, { "x-nextgen-auth-token": "" });
48
+ return NextResponse.next({ request: { headers } });
49
+ }
50
+ if (pathname === proxyPath || pathname.startsWith(`${proxyPath}/`)) {
51
+ return proxyRequest(
52
+ req,
53
+ url,
54
+ proxyPath,
55
+ proxyTimeoutMs,
56
+ onExchangeResponse
57
+ );
58
+ }
59
+ return handleAuth(req, {
60
+ url,
61
+ protectedRoutes,
62
+ loginPath,
63
+ allowedAlgorithms,
64
+ clockSkewMs,
65
+ audience,
66
+ allowedTokenTypes,
67
+ jwksTimeoutMs,
68
+ pathname
69
+ });
70
+ }
71
+ async function proxyRequest(req, authUrl, proxyPath, proxyTimeoutMs, onExchangeResponse) {
72
+ const url = new URL(req.url);
73
+ const suffix = url.pathname.slice(proxyPath.length);
74
+ const target = `${authUrl}${suffix}${url.search}`;
75
+ const upstreamHeaders = new Headers();
76
+ for (const [key, value] of req.headers.entries()) {
77
+ const lower = key.toLowerCase();
78
+ if (!HOP_BY_HOP.has(lower) && !INTERNAL_HEADERS.has(lower)) {
79
+ upstreamHeaders.set(key, value);
80
+ }
81
+ }
82
+ const directIp = req.ip ?? req.headers.get("x-real-ip");
83
+ if (directIp) {
84
+ const existingXff = upstreamHeaders.get("x-forwarded-for");
85
+ upstreamHeaders.set(
86
+ "x-forwarded-for",
87
+ existingXff ? `${existingXff}, ${directIp}` : directIp
88
+ );
89
+ }
90
+ if (!upstreamHeaders.has("x-forwarded-host")) {
91
+ upstreamHeaders.set("x-forwarded-host", url.host);
92
+ }
93
+ if (!upstreamHeaders.has("x-forwarded-proto")) {
94
+ upstreamHeaders.set("x-forwarded-proto", url.protocol.replace(":", ""));
95
+ }
96
+ const hasBody = !["GET", "HEAD"].includes(req.method);
97
+ const upstream = await fetch(target, {
98
+ method: req.method,
99
+ headers: upstreamHeaders,
100
+ body: hasBody ? req.body : void 0,
101
+ redirect: "manual",
102
+ signal: AbortSignal.timeout(proxyTimeoutMs),
103
+ ...hasBody ? { duplex: "half" } : {}
104
+ });
105
+ const responseHeaders = filterResponseHeaders(upstream.headers);
106
+ const setCookies = upstream.headers.getSetCookie?.() ?? [];
107
+ for (const cookie of setCookies) {
108
+ responseHeaders.append("set-cookie", cookie);
109
+ }
110
+ let response = new Response(upstream.body, {
111
+ status: upstream.status,
112
+ headers: responseHeaders
113
+ });
114
+ const isExchange = req.method === "POST" && suffix.startsWith("/sessions/exchange");
115
+ if (isExchange && onExchangeResponse) {
116
+ response = await onExchangeResponse(response);
117
+ }
118
+ return response;
119
+ }
120
+ async function handleAuth(req, opts) {
121
+ const {
122
+ url,
123
+ protectedRoutes,
124
+ loginPath,
125
+ allowedAlgorithms,
126
+ clockSkewMs,
127
+ audience,
128
+ allowedTokenTypes,
129
+ jwksTimeoutMs,
130
+ pathname
131
+ } = opts;
132
+ const authHeader = req.headers.get("authorization");
133
+ const bearerToken = authHeader?.startsWith("Bearer ") ? authHeader.slice(7) : null;
134
+ const cookieToken = req.cookies.get("__nextgen_session")?.value ?? null;
135
+ const token = bearerToken ?? cookieToken;
136
+ const payload = token ? await verifyJwt(token, {
137
+ issuerUrl: url,
138
+ allowedAlgorithms,
139
+ clockSkewMs,
140
+ audience,
141
+ allowedTokenTypes,
142
+ jwksTimeoutMs
143
+ }) : null;
144
+ if (payload && token && payload.sub) {
145
+ const tunnelled2 = tunnelHeaders(req, { "x-nextgen-auth-token": token });
146
+ return NextResponse.next({ request: { headers: tunnelled2 } });
147
+ }
148
+ const tunnelled = tunnelHeaders(req, { "x-nextgen-auth-token": "" });
149
+ const staleNextgenCookies = req.cookies.getAll().filter((c) => c.name.startsWith("__nextgen"));
150
+ if (matchesRoutes(pathname, protectedRoutes)) {
151
+ const loginUrl = new URL(loginPath, req.url);
152
+ loginUrl.searchParams.set("next", pathname);
153
+ const redirect = NextResponse.redirect(loginUrl, { status: 302 });
154
+ for (const cookie of staleNextgenCookies) {
155
+ redirect.cookies.delete(cookie.name);
156
+ }
157
+ return redirect;
158
+ }
159
+ const response = NextResponse.next({ request: { headers: tunnelled } });
160
+ for (const cookie of staleNextgenCookies) {
161
+ response.cookies.delete(cookie.name);
162
+ }
163
+ return response;
164
+ }
165
+ function createProxy(config, options = {}) {
166
+ const mergedOptions = {
167
+ ...options,
168
+ proxyPath: config.proxyPath,
169
+ url: config.url
170
+ };
171
+ return (req) => nextgenMiddleware(req, mergedOptions);
172
+ }
173
+
174
+ export {
175
+ nextgenMiddleware,
176
+ createProxy
177
+ };
@@ -0,0 +1,12 @@
1
+ import {
2
+ useAuthContext
3
+ } from "./chunk-2BFQLJQE.js";
4
+
5
+ // src/useAuth.ts
6
+ function useAuth() {
7
+ return useAuthContext();
8
+ }
9
+
10
+ export {
11
+ useAuth
12
+ };
@@ -0,0 +1,2 @@
1
+ export { ZitadelLogin, ZitadelLogout } from '@zitadel/components';
2
+ export { ZitadelConfig, ZitadelProject, configureZitadel, getApi } from '@zitadel/api/config';
package/dist/client.js ADDED
@@ -0,0 +1,9 @@
1
+ // src/client.ts
2
+ import { ZitadelLogin, ZitadelLogout } from "@zitadel/components";
3
+ import { configureZitadel, getApi } from "@zitadel/api/config";
4
+ export {
5
+ ZitadelLogin,
6
+ ZitadelLogout,
7
+ configureZitadel,
8
+ getApi
9
+ };
@@ -0,0 +1,11 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+ import { AuthResult, NextgenSession } from '@zitadel/sdk-core/types';
4
+
5
+ declare function NextgenProvider({ session, children, }: {
6
+ session: AuthResult | NextgenSession | null;
7
+ children: ReactNode;
8
+ }): react_jsx_runtime.JSX.Element;
9
+ declare function useAuthContext(): AuthResult;
10
+
11
+ export { NextgenProvider, useAuthContext };
@@ -0,0 +1,9 @@
1
+ "use client";
2
+ import {
3
+ NextgenProvider,
4
+ useAuthContext
5
+ } from "./chunk-2BFQLJQE.js";
6
+ export {
7
+ NextgenProvider,
8
+ useAuthContext
9
+ };
@@ -0,0 +1,9 @@
1
+ export { AuthResult, AuthState, NextgenMiddlewareOptions, NextgenSession, UnauthState } from '@zitadel/sdk-core/types';
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';
package/dist/index.js ADDED
@@ -0,0 +1,24 @@
1
+ import {
2
+ createProxy,
3
+ nextgenMiddleware
4
+ } from "./chunk-UTJFJPDR.js";
5
+ import {
6
+ auth
7
+ } from "./chunk-EAUJMJ45.js";
8
+ import "./chunk-5P5THDJF.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
+ };
@@ -0,0 +1,80 @@
1
+ import { ZitadelProject } from '@zitadel/api/config';
2
+ import { NextgenMiddlewareOptions } from '@zitadel/sdk-core/types';
3
+ import { NextRequest, NextResponse } from 'next/server';
4
+
5
+ /**
6
+ * Next.js Edge middleware that handles proxying, JWT verification, and route
7
+ * protection in a single pass.
8
+ *
9
+ * Place this in your `middleware.ts` file:
10
+ *
11
+ * ```ts
12
+ * import { nextgenMiddleware } from "@zitadel/sdk-next/middleware";
13
+ * import type { NextRequest } from "next/server";
14
+ *
15
+ * export function middleware(req: NextRequest) {
16
+ * return nextgenMiddleware(req, {
17
+ * url: process.env.ZITADEL_URL,
18
+ * protectedRoutes: ["/profile"],
19
+ * loginPath: "/login",
20
+ * });
21
+ * }
22
+ *
23
+ * export const config = {
24
+ * matcher: ["/__nextgen/:path*", "/profile/:path*"],
25
+ * };
26
+ * ```
27
+ *
28
+ * @param req - The incoming Next.js edge request.
29
+ * @param options - Middleware configuration options.
30
+ * @returns A `NextResponse` or `Response` to continue, redirect, or proxy.
31
+ */
32
+ declare function nextgenMiddleware(req: NextRequest, options?: NextgenMiddlewareOptions): Promise<NextResponse | Response>;
33
+ /**
34
+ * Options for {@link createProxy} that are separate from the shared
35
+ * {@link ZitadelConfig}. These configure route protection, login
36
+ * redirects, and JWT verification behaviour.
37
+ *
38
+ * `proxyPath` and `url` are omitted because they come from the
39
+ * {@link ZitadelConfig} passed as the first argument.
40
+ */
41
+ type ProxyOptions = Omit<NextgenMiddlewareOptions, 'proxyPath' | 'url'>;
42
+ /**
43
+ * A pre-configured middleware handler returned by {@link createProxy}.
44
+ */
45
+ type ProxyHandler = (req: NextRequest) => Promise<NextResponse | Response>;
46
+ /**
47
+ * Creates a pre-configured middleware handler from the SDK config
48
+ * returned by `configureZitadel()`. This is the derived-service
49
+ * derived service pattern:
50
+ *
51
+ * ```ts
52
+ * // src/zitadel.ts
53
+ * import { configureZitadel } from "@zitadel/api/config";
54
+ * import { createProxy } from "@zitadel/sdk-next/middleware";
55
+ *
56
+ * const zitadel = configureZitadel({
57
+ * projectId: "demo",
58
+ * url: process.env.ZITADEL_URL,
59
+ * });
60
+ *
61
+ * export const proxy = createProxy(zitadel, {
62
+ * protectedRoutes: ["/admin*"],
63
+ * loginPath: "/login",
64
+ * });
65
+ * ```
66
+ *
67
+ * Then in middleware.ts:
68
+ *
69
+ * ```ts
70
+ * import { proxy } from "./zitadel";
71
+ * export const middleware = proxy;
72
+ * ```
73
+ *
74
+ * @param config - The SDK handle from `configureZitadel()`.
75
+ * @param options - Route protection and JWT options.
76
+ * @returns A middleware handler function.
77
+ */
78
+ declare function createProxy(config: ZitadelProject, options?: ProxyOptions): ProxyHandler;
79
+
80
+ export { type ProxyHandler, type ProxyOptions, createProxy, nextgenMiddleware };
@@ -0,0 +1,9 @@
1
+ import {
2
+ createProxy,
3
+ nextgenMiddleware
4
+ } from "./chunk-UTJFJPDR.js";
5
+ import "./chunk-5P5THDJF.js";
6
+ export {
7
+ createProxy,
8
+ nextgenMiddleware
9
+ };
@@ -0,0 +1,2 @@
1
+ export { auth } from './auth.js';
2
+ import '@zitadel/sdk-core/types';
package/dist/server.js ADDED
@@ -0,0 +1,7 @@
1
+ import {
2
+ auth
3
+ } from "./chunk-EAUJMJ45.js";
4
+ import "./chunk-5P5THDJF.js";
5
+ export {
6
+ auth
7
+ };
@@ -0,0 +1 @@
1
+ {"fileNames":[],"fileInfos":[],"root":[],"options":{"composite":true,"declarationMap":true,"emitDeclarationOnly":true,"importHelpers":true,"module":99,"noEmitOnError":true,"noFallthroughCasesInSwitch":true,"noImplicitOverride":true,"noImplicitReturns":true,"noUncheckedIndexedAccess":true,"noUnusedLocals":true,"skipLibCheck":true,"strict":true,"target":9,"tsBuildInfoFile":"./tsconfig.tsbuildinfo"},"version":"5.9.3"}
@@ -0,0 +1,3 @@
1
+ export { AuthResult, AuthState, NextgenMiddlewareOptions, NextgenSession, UnauthState } from '@zitadel/sdk-core/types';
2
+ import '@zitadel/components';
3
+ import '@zitadel/api/config';
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ import "./chunk-6F4PWJZI.js";
@@ -0,0 +1,5 @@
1
+ import { AuthResult } from '@zitadel/sdk-core/types';
2
+
3
+ declare function useAuth(): AuthResult;
4
+
5
+ export { useAuth };
@@ -0,0 +1,8 @@
1
+ "use client";
2
+ import {
3
+ useAuth
4
+ } from "./chunk-XTCHTAIQ.js";
5
+ import "./chunk-2BFQLJQE.js";
6
+ export {
7
+ useAuth
8
+ };
package/package.json ADDED
@@ -0,0 +1,82 @@
1
+ {
2
+ "name": "@zitadel/sdk-next",
3
+ "version": "0.0.0",
4
+ "description": "Next.js helpers and mock auth UI for Zitadel",
5
+ "homepage": "https://github.com/zitadel/nextgen/tree/main/packages/sdk-next#readme",
6
+ "bugs": {
7
+ "url": "https://github.com/zitadel/nextgen/issues"
8
+ },
9
+ "license": "MIT",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/zitadel/nextgen.git",
13
+ "directory": "packages/sdk-next"
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "type": "module",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "import": "./dist/index.js"
23
+ },
24
+ "./server": {
25
+ "types": "./dist/server.d.ts",
26
+ "import": "./dist/server.js"
27
+ },
28
+ "./client": {
29
+ "types": "./dist/client.d.ts",
30
+ "import": "./dist/client.js"
31
+ },
32
+ "./middleware": {
33
+ "types": "./dist/middleware.d.ts",
34
+ "import": "./dist/middleware.js"
35
+ }
36
+ },
37
+ "publishConfig": {
38
+ "access": "public"
39
+ },
40
+ "dependencies": {
41
+ "server-only": "^0.0.1",
42
+ "@zitadel/api": "0.0.0",
43
+ "@zitadel/sdk-core": "0.0.0",
44
+ "@zitadel/components": "0.0.0"
45
+ },
46
+ "peerDependencies": {
47
+ "next": ">=14",
48
+ "react": ">=18",
49
+ "react-dom": ">=18"
50
+ },
51
+ "devDependencies": {
52
+ "@eslint/js": "^9.0.0",
53
+ "tsup": "^8.3.5",
54
+ "typescript": "^5.7.3",
55
+ "@eslint/json": "^0.11.0",
56
+ "@eslint/markdown": "^6.0.0",
57
+ "@testing-library/react": "^16.0.0",
58
+ "@testing-library/user-event": "^14.0.0",
59
+ "@types/react": "^19.2.14",
60
+ "eslint": "^9.0.0",
61
+ "eslint-config-prettier": "^10.0.0",
62
+ "eslint-import-resolver-typescript": "^3.7.0",
63
+ "eslint-plugin-import": "^2.31.0",
64
+ "eslint-plugin-jsx-a11y": "^6.10.0",
65
+ "eslint-plugin-perfectionist": "^4.0.0",
66
+ "eslint-plugin-prettier": "^5.0.0",
67
+ "eslint-plugin-react": "^7.37.0",
68
+ "eslint-plugin-react-hooks": "^5.0.0",
69
+ "eslint-plugin-testing-library": "^7.0.0",
70
+ "jsdom": "^26.0.0",
71
+ "next": "^16.2.4",
72
+ "prettier": "^3.0.0",
73
+ "typescript-eslint": "^8.0.0",
74
+ "vitest": "^3.0.0"
75
+ },
76
+ "scripts": {
77
+ "build": "tsup src/middleware.ts src/auth.ts src/context.tsx src/useAuth.ts src/types.ts src/index.ts src/server.ts src/client.ts --format esm --dts --clean --tsconfig tsconfig.build.json",
78
+ "typecheck": "tsc --noEmit",
79
+ "test": "vitest run --passWithNoTests",
80
+ "lint": "eslint ."
81
+ }
82
+ }