@zitadel/sdk-next 0.1.0-alpha.9 → 0.1.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/README.md +207 -37
- package/dist/auth.d.ts +66 -13
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +162 -7
- package/dist/client.d.ts +27 -2
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +29 -9
- package/dist/components.d.ts +16 -0
- package/dist/components.d.ts.map +1 -0
- package/dist/components.js +15 -0
- package/dist/context.d.ts +21 -10
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +24 -8
- package/dist/index.d.ts +16 -9
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -24
- package/dist/jsx.d.ts +5 -0
- package/dist/lib/jwt.d.ts +9 -0
- package/dist/lib/jwt.d.ts.map +1 -0
- package/dist/lib/jwt.js +7 -0
- package/dist/middleware.d.ts +19 -11
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +304 -9
- package/dist/provider.d.ts +52 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +75 -0
- package/dist/react.d.ts +26 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +24 -0
- package/dist/server.d.ts +13 -2
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +10 -7
- package/dist/session.d.ts +77 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +156 -0
- package/dist/types.d.ts +8 -3
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -1
- package/dist/useAuth.d.ts +17 -5
- package/dist/useAuth.d.ts.map +1 -0
- package/dist/useAuth.js +18 -7
- package/package.json +46 -31
- package/dist/chunk-2BFQLJQE.js +0 -27
- package/dist/chunk-4KENHIG4.js +0 -222
- package/dist/chunk-6F4PWJZI.js +0 -0
- package/dist/chunk-B7S6XMT3.js +0 -41
- package/dist/chunk-OCZMYSFX.js +0 -13
- package/dist/chunk-XTCHTAIQ.js +0 -12
package/dist/chunk-2BFQLJQE.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
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
|
-
};
|
package/dist/chunk-4KENHIG4.js
DELETED
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
base64UrlDecode,
|
|
3
|
-
verifyJwt
|
|
4
|
-
} from "./chunk-OCZMYSFX.js";
|
|
5
|
-
|
|
6
|
-
// src/middleware.ts
|
|
7
|
-
import {
|
|
8
|
-
HOP_BY_HOP,
|
|
9
|
-
INTERNAL_HEADERS,
|
|
10
|
-
filterResponseHeaders,
|
|
11
|
-
matchesRoutes
|
|
12
|
-
} from "@zitadel/sdk-core/middleware";
|
|
13
|
-
import { NextResponse } from "next/server";
|
|
14
|
-
function tunnelHeaders(req, extra) {
|
|
15
|
-
const headers = new Headers(req.headers);
|
|
16
|
-
headers.delete("x-middleware-override-headers");
|
|
17
|
-
const injectedNames = [];
|
|
18
|
-
for (const [name, value] of Object.entries(extra)) {
|
|
19
|
-
headers.set(name, value);
|
|
20
|
-
headers.set(`x-middleware-request-${name}`, value);
|
|
21
|
-
injectedNames.push(name);
|
|
22
|
-
}
|
|
23
|
-
headers.set("x-middleware-override-headers", injectedNames.join(","));
|
|
24
|
-
return headers;
|
|
25
|
-
}
|
|
26
|
-
async function nextgenMiddleware(req, options = {}) {
|
|
27
|
-
const {
|
|
28
|
-
url = process.env.ZITADEL_URL ?? "http://localhost:8080",
|
|
29
|
-
proxyPath = "/__nextgen",
|
|
30
|
-
protectedRoutes = [],
|
|
31
|
-
ignoredRoutes = [],
|
|
32
|
-
loginPath = "/login",
|
|
33
|
-
allowedAlgorithms = ["RS256", "ES256"],
|
|
34
|
-
clockSkewMs = 5e3,
|
|
35
|
-
audience,
|
|
36
|
-
allowedTokenTypes = ["JWT", "at+JWT"],
|
|
37
|
-
jwksTimeoutMs,
|
|
38
|
-
proxyTimeoutMs = 5e3,
|
|
39
|
-
onExchangeResponse
|
|
40
|
-
} = options;
|
|
41
|
-
if (!loginPath.startsWith("/") || loginPath.startsWith("//")) {
|
|
42
|
-
throw new Error(
|
|
43
|
-
`[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.`
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
const { pathname } = new URL(req.url);
|
|
47
|
-
if (matchesRoutes(pathname, ignoredRoutes)) {
|
|
48
|
-
const headers = tunnelHeaders(req, { "x-nextgen-auth-token": "" });
|
|
49
|
-
return NextResponse.next({ request: { headers } });
|
|
50
|
-
}
|
|
51
|
-
if (pathname === proxyPath || pathname.startsWith(`${proxyPath}/`)) {
|
|
52
|
-
return proxyRequest(
|
|
53
|
-
req,
|
|
54
|
-
url,
|
|
55
|
-
proxyPath,
|
|
56
|
-
proxyTimeoutMs,
|
|
57
|
-
onExchangeResponse
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
return handleAuth(req, {
|
|
61
|
-
url,
|
|
62
|
-
protectedRoutes,
|
|
63
|
-
loginPath,
|
|
64
|
-
allowedAlgorithms,
|
|
65
|
-
clockSkewMs,
|
|
66
|
-
audience,
|
|
67
|
-
allowedTokenTypes,
|
|
68
|
-
jwksTimeoutMs,
|
|
69
|
-
pathname
|
|
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
|
-
}
|
|
97
|
-
async function proxyRequest(req, authUrl, proxyPath, proxyTimeoutMs, onExchangeResponse) {
|
|
98
|
-
const url = new URL(req.url);
|
|
99
|
-
const suffix = url.pathname.slice(proxyPath.length);
|
|
100
|
-
const target = `${authUrl}${suffix}${url.search}`;
|
|
101
|
-
const upstreamHeaders = new Headers();
|
|
102
|
-
for (const [key, value] of req.headers.entries()) {
|
|
103
|
-
const lower = key.toLowerCase();
|
|
104
|
-
if (!HOP_BY_HOP.has(lower) && !INTERNAL_HEADERS.has(lower)) {
|
|
105
|
-
upstreamHeaders.set(key, value);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
const directIp = req.ip ?? req.headers.get("x-real-ip");
|
|
109
|
-
if (directIp) {
|
|
110
|
-
const existingXff = upstreamHeaders.get("x-forwarded-for");
|
|
111
|
-
upstreamHeaders.set(
|
|
112
|
-
"x-forwarded-for",
|
|
113
|
-
existingXff ? `${existingXff}, ${directIp}` : directIp
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
if (!upstreamHeaders.has("x-forwarded-host")) {
|
|
117
|
-
upstreamHeaders.set("x-forwarded-host", url.host);
|
|
118
|
-
}
|
|
119
|
-
if (!upstreamHeaders.has("x-forwarded-proto")) {
|
|
120
|
-
upstreamHeaders.set("x-forwarded-proto", url.protocol.replace(":", ""));
|
|
121
|
-
}
|
|
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;
|
|
131
|
-
const upstream = await fetch(target, {
|
|
132
|
-
method: req.method,
|
|
133
|
-
headers: upstreamHeaders,
|
|
134
|
-
body: bodyBuffer,
|
|
135
|
-
redirect: "manual",
|
|
136
|
-
signal: AbortSignal.timeout(proxyTimeoutMs)
|
|
137
|
-
});
|
|
138
|
-
const responseHeaders = filterResponseHeaders(upstream.headers);
|
|
139
|
-
const setCookies = upstream.headers.getSetCookie?.() ?? [];
|
|
140
|
-
for (const cookie of setCookies) {
|
|
141
|
-
responseHeaders.append("set-cookie", cookie);
|
|
142
|
-
}
|
|
143
|
-
let response = new Response(upstream.body, {
|
|
144
|
-
status: upstream.status,
|
|
145
|
-
headers: responseHeaders
|
|
146
|
-
});
|
|
147
|
-
if (isExchangeRequest && onExchangeResponse) {
|
|
148
|
-
response = await onExchangeResponse(response);
|
|
149
|
-
}
|
|
150
|
-
return response;
|
|
151
|
-
}
|
|
152
|
-
async function handleAuth(req, opts) {
|
|
153
|
-
const {
|
|
154
|
-
url,
|
|
155
|
-
protectedRoutes,
|
|
156
|
-
loginPath,
|
|
157
|
-
allowedAlgorithms,
|
|
158
|
-
clockSkewMs,
|
|
159
|
-
audience,
|
|
160
|
-
allowedTokenTypes,
|
|
161
|
-
jwksTimeoutMs,
|
|
162
|
-
pathname
|
|
163
|
-
} = opts;
|
|
164
|
-
const authHeader = req.headers.get("authorization");
|
|
165
|
-
const bearerToken = authHeader?.startsWith("Bearer ") ? authHeader.slice(7) : null;
|
|
166
|
-
const cookieToken = req.cookies.get("__nextgen_session")?.value ?? null;
|
|
167
|
-
const token = bearerToken ?? cookieToken;
|
|
168
|
-
const payload = token ? await verifyJwt(token, {
|
|
169
|
-
issuerUrl: url,
|
|
170
|
-
allowedAlgorithms,
|
|
171
|
-
clockSkewMs,
|
|
172
|
-
audience,
|
|
173
|
-
allowedTokenTypes,
|
|
174
|
-
jwksTimeoutMs
|
|
175
|
-
}) : null;
|
|
176
|
-
if (payload && token && payload.sub) {
|
|
177
|
-
const tunnelled2 = tunnelHeaders(req, { "x-nextgen-auth-token": token });
|
|
178
|
-
return NextResponse.next({ request: { headers: tunnelled2 } });
|
|
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
|
-
}
|
|
193
|
-
const tunnelled = tunnelHeaders(req, { "x-nextgen-auth-token": "" });
|
|
194
|
-
const staleNextgenCookies = req.cookies.getAll().filter((c) => c.name.startsWith("__nextgen"));
|
|
195
|
-
if (matchesRoutes(pathname, protectedRoutes)) {
|
|
196
|
-
const loginUrl = new URL(loginPath, req.url);
|
|
197
|
-
loginUrl.searchParams.set("next", pathname);
|
|
198
|
-
const redirect = NextResponse.redirect(loginUrl, { status: 302 });
|
|
199
|
-
for (const cookie of staleNextgenCookies) {
|
|
200
|
-
redirect.cookies.delete(cookie.name);
|
|
201
|
-
}
|
|
202
|
-
return redirect;
|
|
203
|
-
}
|
|
204
|
-
const response = NextResponse.next({ request: { headers: tunnelled } });
|
|
205
|
-
for (const cookie of staleNextgenCookies) {
|
|
206
|
-
response.cookies.delete(cookie.name);
|
|
207
|
-
}
|
|
208
|
-
return response;
|
|
209
|
-
}
|
|
210
|
-
function createProxy(config, options = {}) {
|
|
211
|
-
const mergedOptions = {
|
|
212
|
-
...options,
|
|
213
|
-
proxyPath: config.proxyPath,
|
|
214
|
-
url: config.url
|
|
215
|
-
};
|
|
216
|
-
return (req) => nextgenMiddleware(req, mergedOptions);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
export {
|
|
220
|
-
nextgenMiddleware,
|
|
221
|
-
createProxy
|
|
222
|
-
};
|
package/dist/chunk-6F4PWJZI.js
DELETED
|
File without changes
|
package/dist/chunk-B7S6XMT3.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
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
|
-
};
|
package/dist/chunk-OCZMYSFX.js
DELETED