@zitadel/sdk-next 0.0.0 → 0.1.0-alpha.10

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/dist/auth.d.ts CHANGED
@@ -3,10 +3,12 @@ import { AuthResult } from '@zitadel/sdk-core/types';
3
3
  /**
4
4
  * Reads the auth state in a React Server Component or Next.js Route Handler.
5
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.
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.
10
12
  *
11
13
  * ```ts
12
14
  * import { auth } from "@zitadel/sdk-next";
@@ -14,7 +16,7 @@ import { AuthResult } from '@zitadel/sdk-core/types';
14
16
  * export default async function Page() {
15
17
  * const session = await auth();
16
18
  * if (!session.isAuthenticated) return <p>Not signed in</p>;
17
- * return <p>Hello {session.session.email}</p>;
19
+ * return <p>Hello {session.session.userId}</p>;
18
20
  * }
19
21
  * ```
20
22
  *
package/dist/auth.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  auth
3
- } from "./chunk-EAUJMJ45.js";
4
- import "./chunk-5P5THDJF.js";
3
+ } from "./chunk-B7S6XMT3.js";
4
+ import "./chunk-OCZMYSFX.js";
5
5
  export {
6
6
  auth
7
7
  };
@@ -1,6 +1,7 @@
1
1
  import {
2
+ base64UrlDecode,
2
3
  verifyJwt
3
- } from "./chunk-5P5THDJF.js";
4
+ } from "./chunk-OCZMYSFX.js";
4
5
 
5
6
  // src/middleware.ts
6
7
  import {
@@ -68,6 +69,31 @@ async function nextgenMiddleware(req, options = {}) {
68
69
  pathname
69
70
  });
70
71
  }
72
+ var DECODER = new TextDecoder();
73
+ function isJwtShaped(token) {
74
+ const parts = token.split(".");
75
+ if (parts.length < 3 || !parts[0]) return false;
76
+ try {
77
+ const header = JSON.parse(
78
+ DECODER.decode(base64UrlDecode(parts[0]))
79
+ );
80
+ return typeof header?.alg === "string" && !("enc" in header);
81
+ } catch {
82
+ return false;
83
+ }
84
+ }
85
+ async function validateOpaqueSessionToken(token, issuerUrl, timeoutMs) {
86
+ try {
87
+ const res = await fetch(`${issuerUrl}/sessions/me`, {
88
+ method: "GET",
89
+ headers: { cookie: `__nextgen_session=${token}` },
90
+ signal: AbortSignal.timeout(timeoutMs)
91
+ });
92
+ return res.ok;
93
+ } catch {
94
+ return false;
95
+ }
96
+ }
71
97
  async function proxyRequest(req, authUrl, proxyPath, proxyTimeoutMs, onExchangeResponse) {
72
98
  const url = new URL(req.url);
73
99
  const suffix = url.pathname.slice(proxyPath.length);
@@ -94,13 +120,20 @@ async function proxyRequest(req, authUrl, proxyPath, proxyTimeoutMs, onExchangeR
94
120
  upstreamHeaders.set("x-forwarded-proto", url.protocol.replace(":", ""));
95
121
  }
96
122
  const hasBody = !["GET", "HEAD"].includes(req.method);
123
+ const isExchangeRequest = req.method === "POST" && suffix.startsWith("/sessions/exchange");
124
+ if (isExchangeRequest && !upstreamHeaders.has("authorization")) {
125
+ const projectId = url.searchParams.get("project_id");
126
+ if (projectId) {
127
+ upstreamHeaders.set("authorization", `Bearer sk_${projectId}`);
128
+ }
129
+ }
130
+ const bodyBuffer = hasBody ? await req.arrayBuffer() : void 0;
97
131
  const upstream = await fetch(target, {
98
132
  method: req.method,
99
133
  headers: upstreamHeaders,
100
- body: hasBody ? req.body : void 0,
134
+ body: bodyBuffer,
101
135
  redirect: "manual",
102
- signal: AbortSignal.timeout(proxyTimeoutMs),
103
- ...hasBody ? { duplex: "half" } : {}
136
+ signal: AbortSignal.timeout(proxyTimeoutMs)
104
137
  });
105
138
  const responseHeaders = filterResponseHeaders(upstream.headers);
106
139
  const setCookies = upstream.headers.getSetCookie?.() ?? [];
@@ -111,8 +144,7 @@ async function proxyRequest(req, authUrl, proxyPath, proxyTimeoutMs, onExchangeR
111
144
  status: upstream.status,
112
145
  headers: responseHeaders
113
146
  });
114
- const isExchange = req.method === "POST" && suffix.startsWith("/sessions/exchange");
115
- if (isExchange && onExchangeResponse) {
147
+ if (isExchangeRequest && onExchangeResponse) {
116
148
  response = await onExchangeResponse(response);
117
149
  }
118
150
  return response;
@@ -145,6 +177,19 @@ async function handleAuth(req, opts) {
145
177
  const tunnelled2 = tunnelHeaders(req, { "x-nextgen-auth-token": token });
146
178
  return NextResponse.next({ request: { headers: tunnelled2 } });
147
179
  }
180
+ if (!payload && cookieToken && !isJwtShaped(cookieToken)) {
181
+ const isValid = await validateOpaqueSessionToken(
182
+ cookieToken,
183
+ url,
184
+ jwksTimeoutMs ?? 5e3
185
+ );
186
+ if (isValid) {
187
+ const tunnelled2 = tunnelHeaders(req, {
188
+ "x-nextgen-auth-token": cookieToken
189
+ });
190
+ return NextResponse.next({ request: { headers: tunnelled2 } });
191
+ }
192
+ }
148
193
  const tunnelled = tunnelHeaders(req, { "x-nextgen-auth-token": "" });
149
194
  const staleNextgenCookies = req.cookies.getAll().filter((c) => c.name.startsWith("__nextgen"));
150
195
  if (matchesRoutes(pathname, protectedRoutes)) {
@@ -0,0 +1,41 @@
1
+ import {
2
+ decodeJwt
3
+ } from "./chunk-OCZMYSFX.js";
4
+
5
+ // src/auth.ts
6
+ import { headers } from "next/headers";
7
+ async function auth() {
8
+ const headerStore = await headers();
9
+ const token = headerStore.get("x-nextgen-auth-token");
10
+ if (!token) {
11
+ return { isAuthenticated: false, session: null };
12
+ }
13
+ try {
14
+ const { payload } = decodeJwt(token);
15
+ if (payload.sub) {
16
+ return {
17
+ isAuthenticated: true,
18
+ session: {
19
+ userId: payload.sub,
20
+ email: payload.email ?? null,
21
+ name: payload.name ?? null,
22
+ token
23
+ }
24
+ };
25
+ }
26
+ } catch {
27
+ }
28
+ return {
29
+ isAuthenticated: true,
30
+ session: {
31
+ userId: "unknown",
32
+ email: null,
33
+ name: null,
34
+ token
35
+ }
36
+ };
37
+ }
38
+
39
+ export {
40
+ auth
41
+ };
@@ -7,6 +7,7 @@ import {
7
7
  } from "@zitadel/sdk-core/jwt";
8
8
 
9
9
  export {
10
+ base64UrlDecode,
10
11
  decodeJwt,
11
12
  verifyJwt
12
13
  };
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  createProxy,
3
3
  nextgenMiddleware
4
- } from "./chunk-UTJFJPDR.js";
4
+ } from "./chunk-4KENHIG4.js";
5
5
  import {
6
6
  auth
7
- } from "./chunk-EAUJMJ45.js";
8
- import "./chunk-5P5THDJF.js";
7
+ } from "./chunk-B7S6XMT3.js";
8
+ import "./chunk-OCZMYSFX.js";
9
9
  import "./chunk-6F4PWJZI.js";
10
10
  import {
11
11
  useAuth
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  createProxy,
3
3
  nextgenMiddleware
4
- } from "./chunk-UTJFJPDR.js";
5
- import "./chunk-5P5THDJF.js";
4
+ } from "./chunk-4KENHIG4.js";
5
+ import "./chunk-OCZMYSFX.js";
6
6
  export {
7
7
  createProxy,
8
8
  nextgenMiddleware
package/dist/server.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  auth
3
- } from "./chunk-EAUJMJ45.js";
4
- import "./chunk-5P5THDJF.js";
3
+ } from "./chunk-B7S6XMT3.js";
4
+ import "./chunk-OCZMYSFX.js";
5
5
  export {
6
6
  auth
7
7
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zitadel/sdk-next",
3
- "version": "0.0.0",
3
+ "version": "0.1.0-alpha.10",
4
4
  "description": "Next.js helpers and mock auth UI for Zitadel",
5
5
  "homepage": "https://github.com/zitadel/nextgen/tree/main/packages/sdk-next#readme",
6
6
  "bugs": {
@@ -39,9 +39,9 @@
39
39
  },
40
40
  "dependencies": {
41
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"
42
+ "@zitadel/api": "0.1.0-alpha.10",
43
+ "@zitadel/components": "0.1.0-alpha.10",
44
+ "@zitadel/sdk-core": "0.1.0-alpha.10"
45
45
  },
46
46
  "peerDependencies": {
47
47
  "next": ">=14",
@@ -1,34 +0,0 @@
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
- };
@@ -1 +0,0 @@
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"}