@civic/auth 0.0.1-beta.18 → 0.0.1-beta.19
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/AuthProvider-Bj_Prt1x.d.ts +21 -0
- package/dist/AuthProvider-DUAoX4G9.d.mts +21 -0
- package/dist/{index-DTimUlkB.d.ts → UserProvider-CMLaYOUD.d.ts} +1 -2
- package/dist/{index-DvjkKpkk.d.mts → UserProvider-Cbm8MZkJ.d.mts} +1 -2
- package/dist/chunk-5UQQYXCX.js +1 -0
- package/dist/chunk-5UQQYXCX.js.map +1 -0
- package/dist/chunk-BFESCRFK.mjs +118 -0
- package/dist/chunk-BFESCRFK.mjs.map +1 -0
- package/dist/{chunk-G3P5TIO2.mjs → chunk-CBQ3HKRV.mjs} +123 -232
- package/dist/chunk-CBQ3HKRV.mjs.map +1 -0
- package/dist/chunk-CRTRMMJ7.js.map +1 -1
- package/dist/{chunk-SEKF2WZX.js → chunk-CZ3AVCKD.js} +16 -71
- package/dist/chunk-CZ3AVCKD.js.map +1 -0
- package/dist/chunk-DJFTZS4P.js +118 -0
- package/dist/chunk-DJFTZS4P.js.map +1 -0
- package/dist/chunk-HTTTZ2BP.mjs +223 -0
- package/dist/chunk-HTTTZ2BP.mjs.map +1 -0
- package/dist/{chunk-RF23Q4V6.js → chunk-O2SODTR3.js} +114 -223
- package/dist/chunk-O2SODTR3.js.map +1 -0
- package/dist/chunk-O6DPCPRH.js +223 -0
- package/dist/chunk-O6DPCPRH.js.map +1 -0
- package/dist/chunk-PMJAV4JJ.mjs +1 -0
- package/dist/chunk-PMJAV4JJ.mjs.map +1 -0
- package/dist/chunk-UADVRCHY.mjs +710 -0
- package/dist/chunk-UADVRCHY.mjs.map +1 -0
- package/dist/chunk-VJVRFKDH.js +710 -0
- package/dist/chunk-VJVRFKDH.js.map +1 -0
- package/dist/{chunk-5XL2ST72.mjs → chunk-X3FQBE22.mjs} +15 -70
- package/dist/chunk-X3FQBE22.mjs.map +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -0
- package/dist/nextjs/client.css +335 -0
- package/dist/nextjs/client.css.map +1 -0
- package/dist/nextjs/client.d.mts +12 -0
- package/dist/nextjs/client.d.ts +12 -0
- package/dist/nextjs/client.js +179 -0
- package/dist/nextjs/client.js.map +1 -0
- package/dist/nextjs/client.mjs +179 -0
- package/dist/nextjs/client.mjs.map +1 -0
- package/dist/nextjs.d.mts +35 -7
- package/dist/nextjs.d.ts +35 -7
- package/dist/nextjs.js +129 -42
- package/dist/nextjs.js.map +1 -1
- package/dist/nextjs.mjs +116 -29
- package/dist/nextjs.mjs.map +1 -1
- package/dist/react.d.mts +7 -31
- package/dist/react.d.ts +7 -31
- package/dist/react.js +15 -835
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +47 -867
- package/dist/react.mjs.map +1 -1
- package/dist/server.d.mts +3 -24
- package/dist/server.d.ts +3 -24
- package/dist/server.js +4 -2
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +4 -2
- package/dist/storage-B2eAQNdv.d.ts +25 -0
- package/dist/storage-BJPUpxhm.d.mts +25 -0
- package/dist/{types-b4c1koXj.d.mts → types-Bqm9OCZN.d.mts} +5 -2
- package/dist/{types-b4c1koXj.d.ts → types-Bqm9OCZN.d.ts} +5 -2
- package/package.json +24 -15
- package/dist/chunk-5XL2ST72.mjs.map +0 -1
- package/dist/chunk-G3P5TIO2.mjs.map +0 -1
- package/dist/chunk-RF23Q4V6.js.map +0 -1
- package/dist/chunk-SEKF2WZX.js.map +0 -1
package/dist/nextjs.js
CHANGED
|
@@ -5,17 +5,25 @@
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
|
|
8
|
+
var _chunkDJFTZS4Pjs = require('./chunk-DJFTZS4P.js');
|
|
8
9
|
|
|
9
10
|
|
|
10
|
-
var _chunkSEKF2WZXjs = require('./chunk-SEKF2WZX.js');
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
|
|
14
|
+
var _chunkCZ3AVCKDjs = require('./chunk-CZ3AVCKD.js');
|
|
14
15
|
|
|
15
16
|
|
|
17
|
+
var _chunkO6DPCPRHjs = require('./chunk-O6DPCPRH.js');
|
|
16
18
|
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
var _chunkO2SODTR3js = require('./chunk-O2SODTR3.js');
|
|
19
27
|
|
|
20
28
|
|
|
21
29
|
|
|
@@ -25,9 +33,9 @@ var _chunkCRTRMMJ7js = require('./chunk-CRTRMMJ7.js');
|
|
|
25
33
|
// src/nextjs/GetUser.ts
|
|
26
34
|
var getUser2 = () => {
|
|
27
35
|
var _a;
|
|
28
|
-
const clientStorage = new (0,
|
|
29
|
-
const userSession = new (0,
|
|
30
|
-
const tokens =
|
|
36
|
+
const clientStorage = new (0, _chunkDJFTZS4Pjs.NextjsClientStorage)();
|
|
37
|
+
const userSession = new (0, _chunkO2SODTR3js.GenericUserSession)(clientStorage);
|
|
38
|
+
const tokens = _chunkO2SODTR3js.retrieveTokens.call(void 0, clientStorage);
|
|
31
39
|
const user = userSession.get();
|
|
32
40
|
if (!user || !tokens) return null;
|
|
33
41
|
return _chunkCRTRMMJ7js.__spreadProps.call(void 0, _chunkCRTRMMJ7js.__spreadValues.call(void 0, {}, user), {
|
|
@@ -54,7 +62,7 @@ var matchesGlobs = (pathname, patterns) => patterns.some((pattern) => {
|
|
|
54
62
|
return matchGlob(pathname, pattern);
|
|
55
63
|
});
|
|
56
64
|
var applyAuth = (authConfig, request) => _chunkCRTRMMJ7js.__async.call(void 0, void 0, null, function* () {
|
|
57
|
-
const authConfigWithDefaults =
|
|
65
|
+
const authConfigWithDefaults = _chunkCZ3AVCKDjs.resolveAuthConfig.call(void 0, authConfig);
|
|
58
66
|
const isAuthenticated = !!request.cookies.get("id_token");
|
|
59
67
|
if (request.nextUrl.pathname === authConfigWithDefaults.loginUrl && request.method === "GET") {
|
|
60
68
|
console.log("\u2192 Skipping auth check - this is the login URL");
|
|
@@ -69,14 +77,14 @@ var applyAuth = (authConfig, request) => _chunkCRTRMMJ7js.__async.call(void 0, v
|
|
|
69
77
|
return void 0;
|
|
70
78
|
}
|
|
71
79
|
if (!isAuthenticated) {
|
|
72
|
-
console.log("\u2192 No valid token found - redirecting to login");
|
|
73
80
|
const loginUrl = new URL(authConfigWithDefaults.loginUrl, request.url);
|
|
81
|
+
console.log("\u2192 No valid token found - redirecting to login", loginUrl);
|
|
74
82
|
return _serverjs.NextResponse.redirect(loginUrl);
|
|
75
83
|
}
|
|
76
84
|
console.log("\u2192 Auth check passed");
|
|
77
85
|
return void 0;
|
|
78
86
|
});
|
|
79
|
-
var authMiddleware = (authConfig =
|
|
87
|
+
var authMiddleware = (authConfig = _chunkCZ3AVCKDjs.defaultAuthConfig) => (request) => _chunkCRTRMMJ7js.__async.call(void 0, void 0, null, function* () {
|
|
80
88
|
const response = yield applyAuth(authConfig, request);
|
|
81
89
|
if (response) return response;
|
|
82
90
|
return _serverjs.NextResponse.next();
|
|
@@ -101,7 +109,8 @@ function auth(authConfig = {}) {
|
|
|
101
109
|
// src/nextjs/routeHandler.ts
|
|
102
110
|
|
|
103
111
|
var _cachejs = require('next/cache.js');
|
|
104
|
-
var
|
|
112
|
+
var _headersjs = require('next/headers.js');
|
|
113
|
+
var logger = _chunkCZ3AVCKDjs.loggers.nextjs.handlers.auth;
|
|
105
114
|
var AuthError = class extends Error {
|
|
106
115
|
constructor(message, status = 401) {
|
|
107
116
|
super(message);
|
|
@@ -109,48 +118,121 @@ var AuthError = class extends Error {
|
|
|
109
118
|
this.name = "AuthError";
|
|
110
119
|
}
|
|
111
120
|
};
|
|
112
|
-
function handleChallenge() {
|
|
121
|
+
function handleChallenge(config) {
|
|
113
122
|
return _chunkCRTRMMJ7js.__async.call(void 0, this, null, function* () {
|
|
114
|
-
|
|
115
|
-
const
|
|
123
|
+
var _a, _b;
|
|
124
|
+
const cookieStorage = new (0, _chunkDJFTZS4Pjs.NextjsCookieStorage)((_b = (_a = config.cookies) == null ? void 0 : _a.tokens) != null ? _b : {});
|
|
125
|
+
const pkceProducer = new (0, _chunkO2SODTR3js.GenericPublicClientPKCEProducer)(cookieStorage);
|
|
116
126
|
const challenge = yield pkceProducer.getCodeChallenge();
|
|
117
127
|
return _serverjs.NextResponse.json({ status: "success", challenge });
|
|
118
128
|
});
|
|
119
129
|
}
|
|
120
|
-
function
|
|
130
|
+
function performTokenExchangeAndSetCookies(request, config, code, state) {
|
|
121
131
|
return _chunkCRTRMMJ7js.__async.call(void 0, this, null, function* () {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
);
|
|
126
|
-
response2.headers.set("Content-Type", "text/html; charset=utf-8");
|
|
127
|
-
console.log(
|
|
128
|
-
`handleCallback no code_verifier found, returning ${_chunkRF23Q4V6js.TOKEN_EXCHANGE_TRIGGER_TEXT}`
|
|
129
|
-
);
|
|
130
|
-
return response2;
|
|
131
|
-
}
|
|
132
|
-
const code = request.nextUrl.searchParams.get("code");
|
|
133
|
-
const state = request.nextUrl.searchParams.get("state");
|
|
134
|
-
if (!code || !state) throw new AuthError("Bad parameters", 400);
|
|
135
|
-
const resolvedConfigs = _chunkSEKF2WZXjs.resolveAuthConfig.call(void 0, config);
|
|
136
|
-
const cookieStorage = new (0, _chunkSEKF2WZXjs.NextjsCookieStorage)(resolvedConfigs.cookies.tokens);
|
|
137
|
-
const callbackUrl = _chunkSEKF2WZXjs.resolveCallbackUrl.call(void 0, resolvedConfigs, request.url);
|
|
132
|
+
const resolvedConfigs = _chunkCZ3AVCKDjs.resolveAuthConfig.call(void 0, config);
|
|
133
|
+
const cookieStorage = new (0, _chunkDJFTZS4Pjs.NextjsCookieStorage)(resolvedConfigs.cookies.tokens);
|
|
134
|
+
const callbackUrl = _chunkDJFTZS4Pjs.resolveCallbackUrl.call(void 0, resolvedConfigs, request.url);
|
|
138
135
|
try {
|
|
139
|
-
yield
|
|
136
|
+
yield _chunkO6DPCPRHjs.resolveOAuthAccessCode.call(void 0, code, state, cookieStorage, _chunkCRTRMMJ7js.__spreadProps.call(void 0, _chunkCRTRMMJ7js.__spreadValues.call(void 0, {}, resolvedConfigs), {
|
|
140
137
|
redirectUrl: callbackUrl
|
|
141
138
|
}));
|
|
142
139
|
} catch (error) {
|
|
143
140
|
logger.error("Token exchange failed:", error);
|
|
144
141
|
throw new AuthError("Failed to authenticate user", 401);
|
|
145
142
|
}
|
|
146
|
-
const user = yield
|
|
143
|
+
const user = yield _chunkO2SODTR3js.getUser.call(void 0, cookieStorage);
|
|
147
144
|
if (!user) {
|
|
148
145
|
throw new AuthError("Failed to get user info", 401);
|
|
149
146
|
}
|
|
150
|
-
const clientStorage = new (0,
|
|
151
|
-
const userSession = new (0,
|
|
147
|
+
const clientStorage = new (0, _chunkDJFTZS4Pjs.NextjsClientStorage)();
|
|
148
|
+
const userSession = new (0, _chunkO2SODTR3js.GenericUserSession)(clientStorage);
|
|
152
149
|
userSession.set(user);
|
|
153
|
-
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
function handleCallback(request, config) {
|
|
153
|
+
return _chunkCRTRMMJ7js.__async.call(void 0, this, null, function* () {
|
|
154
|
+
const resolvedConfigs = _chunkCZ3AVCKDjs.resolveAuthConfig.call(void 0, config);
|
|
155
|
+
console.log("handleCallback", { request, resolvedConfigs });
|
|
156
|
+
const code = request.nextUrl.searchParams.get("code");
|
|
157
|
+
const state = request.nextUrl.searchParams.get("state") || "";
|
|
158
|
+
if (!code || !state) throw new AuthError("Bad parameters", 400);
|
|
159
|
+
console.log("handleCallback", { code, state, cookies: _headersjs.cookies.call(void 0, ) });
|
|
160
|
+
if (!request.cookies.get("code_verifier" /* COOKIE_NAME */)) {
|
|
161
|
+
console.log("handleCallback no code_verifier found", {
|
|
162
|
+
state,
|
|
163
|
+
serverTokenExchange: _chunkO2SODTR3js.serverTokenExchangeFromState.call(void 0, `${state}`)
|
|
164
|
+
});
|
|
165
|
+
let response2 = new (0, _serverjs.NextResponse)(
|
|
166
|
+
`<html><body><span style="display:none">${_chunkO2SODTR3js.TOKEN_EXCHANGE_TRIGGER_TEXT}</span></body></html>`
|
|
167
|
+
);
|
|
168
|
+
if (state && _chunkO2SODTR3js.serverTokenExchangeFromState.call(void 0, state)) {
|
|
169
|
+
console.log(
|
|
170
|
+
"handleCallback serverTokenExchangeFromState, launching redirect page...",
|
|
171
|
+
{
|
|
172
|
+
requestUrl: request.url,
|
|
173
|
+
configCallbackUrl: resolvedConfigs.callbackUrl
|
|
174
|
+
}
|
|
175
|
+
);
|
|
176
|
+
const requestUrl = new URL(request.url);
|
|
177
|
+
const fetchUrl = `${resolvedConfigs.callbackUrl}?${requestUrl.searchParams.toString()}&sameDomainServerTokenExchange=true`;
|
|
178
|
+
response2 = new (0, _serverjs.NextResponse)(
|
|
179
|
+
`<html>
|
|
180
|
+
<body>
|
|
181
|
+
<span style="display:none">
|
|
182
|
+
<script>
|
|
183
|
+
window.onload = function () {
|
|
184
|
+
fetch('${fetchUrl}').then((response) => {
|
|
185
|
+
response.json().then((jsonResponse) => {
|
|
186
|
+
console.log('fetch jsonResponse', jsonResponse);
|
|
187
|
+
if (jsonResponse.redirectUrl) {
|
|
188
|
+
console.log('handleCallback serverTokenExchangeFromState, redirecting');
|
|
189
|
+
window.location.href = jsonResponse.redirectUrl;
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
};
|
|
194
|
+
</script>
|
|
195
|
+
</span>
|
|
196
|
+
</body>
|
|
197
|
+
</html>
|
|
198
|
+
`
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
response2.headers.set("Content-Type", "text/html; charset=utf-8");
|
|
202
|
+
console.log(
|
|
203
|
+
`handleCallback no code_verifier found, returning ${_chunkO2SODTR3js.TOKEN_EXCHANGE_TRIGGER_TEXT}`
|
|
204
|
+
);
|
|
205
|
+
return response2;
|
|
206
|
+
}
|
|
207
|
+
yield performTokenExchangeAndSetCookies(
|
|
208
|
+
request,
|
|
209
|
+
resolvedConfigs,
|
|
210
|
+
code,
|
|
211
|
+
state
|
|
212
|
+
);
|
|
213
|
+
if (request.url.includes("sameDomainServerTokenExchange=true")) {
|
|
214
|
+
console.log(
|
|
215
|
+
"handleCallback sameDomainServerTokenExchange = true, returnining redirectUrl",
|
|
216
|
+
resolvedConfigs.appUrl
|
|
217
|
+
);
|
|
218
|
+
return _serverjs.NextResponse.json({
|
|
219
|
+
status: "success",
|
|
220
|
+
redirectUrl: resolvedConfigs.appUrl
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
if (_chunkO2SODTR3js.serverTokenExchangeFromState.call(void 0, state)) {
|
|
224
|
+
console.log(
|
|
225
|
+
"handleCallback serverTokenExchangeFromState, redirect to config.appUrl",
|
|
226
|
+
resolvedConfigs.appUrl
|
|
227
|
+
);
|
|
228
|
+
if (!resolvedConfigs.appUrl) {
|
|
229
|
+
throw new Error("appUrl not defined in config. Cannot redirect.");
|
|
230
|
+
}
|
|
231
|
+
return _serverjs.NextResponse.redirect(`${resolvedConfigs.appUrl}`);
|
|
232
|
+
}
|
|
233
|
+
const response = new (0, _serverjs.NextResponse)(
|
|
234
|
+
`<html><span style="display:none">${_chunkO2SODTR3js.TOKEN_EXCHANGE_SUCCESS_TEXT}</span></html>`
|
|
235
|
+
);
|
|
154
236
|
response.headers.set("Content-Type", "text/html; charset=utf-8");
|
|
155
237
|
return response;
|
|
156
238
|
});
|
|
@@ -163,17 +245,17 @@ var getAbsoluteRedirectPath = (redirectPath, currentBasePath) => {
|
|
|
163
245
|
};
|
|
164
246
|
function handleLogout(request, config) {
|
|
165
247
|
return _chunkCRTRMMJ7js.__async.call(void 0, this, null, function* () {
|
|
166
|
-
var _a;
|
|
167
|
-
const resolvedConfigs =
|
|
248
|
+
var _a, _b;
|
|
249
|
+
const resolvedConfigs = _chunkCZ3AVCKDjs.resolveAuthConfig.call(void 0, config);
|
|
168
250
|
const defaultRedirectPath = (_a = resolvedConfigs.loginUrl) != null ? _a : "/";
|
|
169
251
|
const redirectTarget = new URL(request.url).searchParams.get("redirect") || defaultRedirectPath;
|
|
170
252
|
const isAbsoluteRedirect = /^(https?:\/\/|www\.).+/i.test(redirectTarget);
|
|
171
253
|
const finalRedirectUrl = getAbsoluteRedirectPath(
|
|
172
254
|
redirectTarget,
|
|
173
|
-
new URL(request.url).origin
|
|
255
|
+
new URL((_b = resolvedConfigs.appUrl) != null ? _b : request.url).origin
|
|
174
256
|
);
|
|
175
257
|
const response = _serverjs.NextResponse.redirect(finalRedirectUrl);
|
|
176
|
-
|
|
258
|
+
_chunkDJFTZS4Pjs.clearAuthCookies.call(void 0, config);
|
|
177
259
|
try {
|
|
178
260
|
_cachejs.revalidatePath.call(void 0, isAbsoluteRedirect ? finalRedirectUrl : redirectTarget);
|
|
179
261
|
} catch (error) {
|
|
@@ -183,14 +265,14 @@ function handleLogout(request, config) {
|
|
|
183
265
|
});
|
|
184
266
|
}
|
|
185
267
|
var handler = (authConfig = {}) => (request) => _chunkCRTRMMJ7js.__async.call(void 0, void 0, null, function* () {
|
|
186
|
-
const config =
|
|
268
|
+
const config = _chunkCZ3AVCKDjs.resolveAuthConfig.call(void 0, authConfig);
|
|
187
269
|
try {
|
|
188
270
|
const pathname = request.nextUrl.pathname;
|
|
189
271
|
const pathSegments = pathname.split("/");
|
|
190
272
|
const lastSegment = pathSegments[pathSegments.length - 1];
|
|
191
273
|
switch (lastSegment) {
|
|
192
274
|
case "challenge":
|
|
193
|
-
return yield handleChallenge();
|
|
275
|
+
return yield handleChallenge(config);
|
|
194
276
|
case "callback":
|
|
195
277
|
return yield handleCallback(request, config);
|
|
196
278
|
case "logout":
|
|
@@ -203,7 +285,7 @@ var handler = (authConfig = {}) => (request) => _chunkCRTRMMJ7js.__async.call(vo
|
|
|
203
285
|
const status = error instanceof AuthError ? error.status : 500;
|
|
204
286
|
const message = error instanceof Error ? error.message : "Authentication failed";
|
|
205
287
|
const response = _serverjs.NextResponse.json({ error: message }, { status });
|
|
206
|
-
|
|
288
|
+
_chunkDJFTZS4Pjs.clearAuthCookies.call(void 0, config);
|
|
207
289
|
return response;
|
|
208
290
|
}
|
|
209
291
|
});
|
|
@@ -214,5 +296,10 @@ var handler = (authConfig = {}) => (request) => _chunkCRTRMMJ7js.__async.call(vo
|
|
|
214
296
|
|
|
215
297
|
|
|
216
298
|
|
|
217
|
-
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
exports.NextjsClientStorage = _chunkDJFTZS4Pjs.NextjsClientStorage; exports.NextjsCookieStorage = _chunkDJFTZS4Pjs.NextjsCookieStorage; exports.auth = auth; exports.authMiddleware = authMiddleware; exports.clearAuthCookies = _chunkDJFTZS4Pjs.clearAuthCookies; exports.createCivicAuthPlugin = _chunkCZ3AVCKDjs.createCivicAuthPlugin; exports.createTokenCookies = _chunkDJFTZS4Pjs.createTokenCookies; exports.createUserInfoCookie = _chunkDJFTZS4Pjs.createUserInfoCookie; exports.getUser = getUser2; exports.handler = handler; exports.withAuth = withAuth;
|
|
218
305
|
//# sourceMappingURL=nextjs.js.map
|
package/dist/nextjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/lucas/dev/civic/civic-auth/packages/civic-auth-client/dist/nextjs.js","../src/nextjs/GetUser.ts","../src/nextjs/middleware.ts","../src/nextjs/routeHandler.ts"],"names":["getUser","NextResponse","response"],"mappings":"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","file":"/Users/lucas/dev/civic/civic-auth/packages/civic-auth-client/dist/nextjs.js","sourcesContent":[null,"/**\n * Used on the server-side to get the user object from the cookie\n */\nimport { User } from \"@/types\";\nimport { GenericUserSession } from \"@/shared/UserSession\";\nimport { NextjsClientStorage } from \"@/nextjs/cookies\";\nimport { retrieveTokens } from \"@/shared/util\";\n\nexport const getUser = (): User | null => {\n const clientStorage = new NextjsClientStorage();\n const userSession = new GenericUserSession(clientStorage);\n const tokens = retrieveTokens(clientStorage);\n const user = userSession.get();\n if (!user || !tokens) return null;\n\n return {\n ...user!,\n idToken: tokens.id_token,\n accessToken: tokens.access_token,\n refreshToken: tokens.refresh_token ?? \"\",\n } as User;\n};\n","/**\n * Authenticates the user on all requests by checking the token cookie\n *\n * Usage:\n * Option 1: use if no other middleware (e.g. no next-intl etc)\n * export default authMiddleware();\n *\n * Option 2: use if other middleware is needed - default auth config\n * export default withAuth((request) => {\n * console.log('in custom middleware', request.nextUrl.pathname);\n * return NextResponse.next();\n * })\n *\n * Option 3: use if other middleware is needed - specifying auth config\n * const withCivicAuth = auth({ loginUrl: '/login', include: ['/[.*]/user'] })\n * export default withCivicAuth((request) => {\n * console.log('in custom middleware', request.url);\n * return NextResponse.next();\n * })\n *\n */\nimport { NextRequest, NextResponse } from \"next/server.js\";\nimport picomatch from \"picomatch\";\nimport {\n AuthConfig,\n defaultAuthConfig,\n resolveAuthConfig,\n} from \"@/nextjs/config.js\";\n\ntype Middleware = (\n request: NextRequest,\n) => Promise<NextResponse> | NextResponse;\n\n// Matches globs:\n// Examples:\n// /user\n// /user/*\n// /user/**/info\nconst matchGlob = (pathname: string, globPattern: string) => {\n const matches = picomatch(globPattern);\n return matches(pathname);\n};\n\n// Matches globs:\n// Examples:\n// /user\n// /user/*\n// /user/**/info\nconst matchesGlobs = (pathname: string, patterns: string[]) =>\n patterns.some((pattern) => {\n if (!pattern) return false;\n console.log(\"matching\", {\n pattern,\n pathname,\n match: matchGlob(pathname, pattern),\n });\n return matchGlob(pathname, pattern);\n });\n\n// internal - used by all exported functions\nconst applyAuth = async (\n authConfig: AuthConfig,\n request: NextRequest,\n): Promise<NextResponse | undefined> => {\n const authConfigWithDefaults = resolveAuthConfig(authConfig);\n\n // Check for any valid auth token\n const isAuthenticated = !!request.cookies.get(\"id_token\");\n\n // skip auth check for redirect to login url\n if (\n request.nextUrl.pathname === authConfigWithDefaults.loginUrl &&\n request.method === \"GET\"\n ) {\n console.log(\"→ Skipping auth check - this is the login URL\");\n return undefined;\n }\n\n if (!matchesGlobs(request.nextUrl.pathname, authConfigWithDefaults.include)) {\n console.log(\"→ Skipping auth check - path not in include patterns\");\n return undefined;\n }\n\n if (matchesGlobs(request.nextUrl.pathname, authConfigWithDefaults.exclude)) {\n console.log(\"→ Skipping auth check - path in exclude patterns\");\n return undefined;\n }\n\n // Check for either token type\n if (!isAuthenticated) {\n console.log(\"→ No valid token found - redirecting to login\");\n const loginUrl = new URL(authConfigWithDefaults.loginUrl, request.url);\n return NextResponse.redirect(loginUrl);\n }\n\n console.log(\"→ Auth check passed\");\n return undefined;\n};\n\n/**\n *\n * Use this when auth is the only middleware you need.\n * Usage:\n *\n * export default authMiddleware({ loginUrl = '/login' }); // or just authMiddleware();\n *\n */\nexport const authMiddleware =\n (authConfig = defaultAuthConfig) =>\n async (request: NextRequest): Promise<NextResponse> => {\n const response = await applyAuth(authConfig, request);\n if (response) return response;\n\n // NextJS doesn't do middleware chaining yet, so this does not mean\n // \"call the next middleware\" - it means \"continue to the route handler\"\n return NextResponse.next();\n };\n\n/**\n * Usage:\n *\n * export default withAuth(async (request) => {\n * console.log('my middleware');\n * return NextResponse.next();\n * })\n */\n// use this when you have your own middleware to chain\nexport function withAuth(\n middleware: Middleware,\n): (request: NextRequest) => Promise<NextResponse> {\n return async (request: NextRequest): Promise<NextResponse> => {\n const response = await applyAuth({}, request);\n if (response) return response;\n return middleware(request);\n };\n}\n\n/**\n * Use this when you want to configure the middleware here (an alternative is to do it in the next.config file)\n *\n * Usage:\n *\n * const withAuth = auth({ loginUrl = '/login' }); // or just auth();\n *\n * export default withAuth(async (request) => {\n * console.log('my middleware');\n * return NextResponse.next();\n * })\n *\n */\nexport function auth(authConfig: AuthConfig = {}) {\n return (\n middleware: Middleware,\n ): ((request: NextRequest) => Promise<NextResponse>) => {\n return async (request: NextRequest): Promise<NextResponse> => {\n const response = await applyAuth(authConfig, request);\n if (response) return response;\n return middleware(request);\n };\n };\n}\n","import { NextRequest, NextResponse } from \"next/server.js\";\nimport { revalidatePath } from \"next/cache.js\";\nimport { AuthConfig, resolveAuthConfig } from \"@/nextjs/config.js\";\nimport { loggers } from \"@/lib/logger.js\";\nimport {\n clearAuthCookies,\n NextjsClientStorage,\n NextjsCookieStorage,\n} from \"@/nextjs/cookies.js\";\nimport { GenericPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport { resolveOAuthAccessCode } from \"@/server/login.js\";\nimport { getUser } from \"@/shared/session.js\";\nimport { resolveCallbackUrl } from \"@/nextjs/utils.js\";\nimport { GenericUserSession } from \"@/shared/UserSession.js\";\nimport { TOKEN_EXCHANGE_TRIGGER_TEXT } from \"@/constants\";\n\nconst logger = loggers.nextjs.handlers.auth;\n\nclass AuthError extends Error {\n constructor(\n message: string,\n public readonly status: number = 401,\n ) {\n super(message);\n this.name = \"AuthError\";\n }\n}\n\n/**\n * create a code verifier and challenge for PKCE\n * saving the verifier in a cookie for later use\n * @returns {Promise<NextResponse>}\n */\nasync function handleChallenge(): Promise<NextResponse> {\n const cookieStorage = new NextjsCookieStorage();\n const pkceProducer = new GenericPublicClientPKCEProducer(cookieStorage);\n\n const challenge = await pkceProducer.getCodeChallenge();\n\n return NextResponse.json({ status: \"success\", challenge });\n}\n\nasync function handleCallback(\n request: NextRequest,\n config: AuthConfig,\n): Promise<NextResponse> {\n // If we have a code_verifier cookie, we can do a token exchange.\n // Otherwise, just render an empty page.\n // The initial redirect back from the auth server does not send cookies, because the redirect is from a 3rd-party domain.\n // The client will make an additional call to this route with cookies included, at which point we do the token exchange.\n if (!request.cookies.get(\"code_verifier\")) {\n const response = new NextResponse(\n `<html><body><span style=\"display:none\">${TOKEN_EXCHANGE_TRIGGER_TEXT}</span></body></html>`,\n );\n response.headers.set(\"Content-Type\", \"text/html; charset=utf-8\");\n console.log(\n `handleCallback no code_verifier found, returning ${TOKEN_EXCHANGE_TRIGGER_TEXT}`,\n );\n return response;\n }\n const code = request.nextUrl.searchParams.get(\"code\");\n const state = request.nextUrl.searchParams.get(\"state\");\n if (!code || !state) throw new AuthError(\"Bad parameters\", 400);\n\n const resolvedConfigs = resolveAuthConfig(config);\n const cookieStorage = new NextjsCookieStorage(resolvedConfigs.cookies.tokens);\n\n const callbackUrl = resolveCallbackUrl(resolvedConfigs, request.url);\n try {\n await resolveOAuthAccessCode(code, state, cookieStorage, {\n ...resolvedConfigs,\n redirectUrl: callbackUrl,\n });\n } catch (error) {\n logger.error(\"Token exchange failed:\", error);\n throw new AuthError(\"Failed to authenticate user\", 401);\n }\n\n const user = await getUser(cookieStorage);\n if (!user) {\n throw new AuthError(\"Failed to get user info\", 401);\n }\n\n const clientStorage = new NextjsClientStorage();\n const userSession = new GenericUserSession(clientStorage);\n userSession.set(user);\n\n // return an empty HTML response so the iframe doesn't show any response\n // in the short moment between the redirect and the parent window\n // acknowledging the redirect and closing the iframe\n const response = new NextResponse(`<html></html>`);\n response.headers.set(\"Content-Type\", \"text/html; charset=utf-8\");\n return response;\n}\n\n/**\n * If redirectPath is an absolute path, return it as-is.\n * Otherwise for relative paths, append it to the current domain.\n * @param redirectPath\n * @returns\n */\nconst getAbsoluteRedirectPath = (\n redirectPath: string,\n currentBasePath: string,\n) => {\n // Check if the redirectPath is an absolute URL\n if (/^(https?:\\/\\/|www\\.).+/i.test(redirectPath)) {\n return redirectPath; // Return as-is if it's an absolute URL\n }\n return new URL(redirectPath, currentBasePath).href;\n};\n\nasync function handleLogout(\n request: NextRequest,\n config: AuthConfig,\n): Promise<NextResponse> {\n const resolvedConfigs = resolveAuthConfig(config);\n const defaultRedirectPath = resolvedConfigs.loginUrl ?? \"/\";\n const redirectTarget =\n new URL(request.url).searchParams.get(\"redirect\") || defaultRedirectPath;\n const isAbsoluteRedirect = /^(https?:\\/\\/|www\\.).+/i.test(redirectTarget);\n const finalRedirectUrl = getAbsoluteRedirectPath(\n redirectTarget,\n new URL(request.url).origin,\n );\n\n const response = NextResponse.redirect(finalRedirectUrl);\n\n clearAuthCookies();\n\n try {\n revalidatePath(isAbsoluteRedirect ? finalRedirectUrl : redirectTarget);\n } catch (error) {\n logger.warn(\"Failed to revalidate path after logout:\", error);\n }\n\n return response;\n}\n\n/**\n * Creates an authentication handler for Next.js API routes\n *\n * Usage:\n * ```ts\n * // app/api/auth/[...civicauth]/route.ts\n * import { handler } from '@civic/auth/nextjs'\n * export const GET = handler({\n * // optional config overrides\n * })\n * ```\n */\nexport const handler =\n (authConfig = {}) =>\n async (request: NextRequest): Promise<NextResponse> => {\n const config = resolveAuthConfig(authConfig);\n\n try {\n const pathname = request.nextUrl.pathname;\n const pathSegments = pathname.split(\"/\");\n const lastSegment = pathSegments[pathSegments.length - 1];\n\n switch (lastSegment) {\n case \"challenge\":\n return await handleChallenge();\n case \"callback\":\n return await handleCallback(request, config);\n case \"logout\":\n return await handleLogout(request, config);\n default:\n throw new AuthError(`Invalid auth route: ${pathname}`, 404);\n }\n } catch (error) {\n logger.error(\"Auth handler error:\", error);\n\n const status = error instanceof AuthError ? error.status : 500;\n const message =\n error instanceof Error ? error.message : \"Authentication failed\";\n\n const response = NextResponse.json({ error: message }, { status });\n\n clearAuthCookies();\n return response;\n }\n };\n"]}
|
|
1
|
+
{"version":3,"sources":["/Users/kevincolgan/code/civic-auth/packages/civic-auth-client/dist/nextjs.js","../src/nextjs/GetUser.ts","../src/nextjs/middleware.ts","../src/nextjs/routeHandler.ts"],"names":["getUser","NextResponse","response"],"mappings":"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","file":"/Users/kevincolgan/code/civic-auth/packages/civic-auth-client/dist/nextjs.js","sourcesContent":[null,"/**\n * Used on the server-side to get the user object from the cookie\n */\nimport { User } from \"@/types\";\nimport { GenericUserSession } from \"@/shared/UserSession\";\nimport { NextjsClientStorage } from \"@/nextjs/cookies\";\nimport { retrieveTokens } from \"@/shared/util\";\n\nexport const getUser = (): User | null => {\n const clientStorage = new NextjsClientStorage();\n const userSession = new GenericUserSession(clientStorage);\n const tokens = retrieveTokens(clientStorage);\n const user = userSession.get();\n if (!user || !tokens) return null;\n\n return {\n ...user!,\n idToken: tokens.id_token,\n accessToken: tokens.access_token,\n refreshToken: tokens.refresh_token ?? \"\",\n } as User;\n};\n","/**\n * Authenticates the user on all requests by checking the token cookie\n *\n * Usage:\n * Option 1: use if no other middleware (e.g. no next-intl etc)\n * export default authMiddleware();\n *\n * Option 2: use if other middleware is needed - default auth config\n * export default withAuth((request) => {\n * console.log('in custom middleware', request.nextUrl.pathname);\n * return NextResponse.next();\n * })\n *\n * Option 3: use if other middleware is needed - specifying auth config\n * const withCivicAuth = auth({ loginUrl: '/login', include: ['/[.*]/user'] })\n * export default withCivicAuth((request) => {\n * console.log('in custom middleware', request.url);\n * return NextResponse.next();\n * })\n *\n */\nimport { NextRequest, NextResponse } from \"next/server.js\";\nimport picomatch from \"picomatch\";\nimport {\n AuthConfig,\n defaultAuthConfig,\n resolveAuthConfig,\n} from \"@/nextjs/config.js\";\n\ntype Middleware = (\n request: NextRequest,\n) => Promise<NextResponse> | NextResponse;\n\n// Matches globs:\n// Examples:\n// /user\n// /user/*\n// /user/**/info\nconst matchGlob = (pathname: string, globPattern: string) => {\n const matches = picomatch(globPattern);\n return matches(pathname);\n};\n\n// Matches globs:\n// Examples:\n// /user\n// /user/*\n// /user/**/info\nconst matchesGlobs = (pathname: string, patterns: string[]) =>\n patterns.some((pattern) => {\n if (!pattern) return false;\n console.log(\"matching\", {\n pattern,\n pathname,\n match: matchGlob(pathname, pattern),\n });\n return matchGlob(pathname, pattern);\n });\n\n// internal - used by all exported functions\nconst applyAuth = async (\n authConfig: AuthConfig,\n request: NextRequest,\n): Promise<NextResponse | undefined> => {\n const authConfigWithDefaults = resolveAuthConfig(authConfig);\n // Check for any valid auth token\n const isAuthenticated = !!request.cookies.get(\"id_token\");\n\n // skip auth check for redirect to login url\n if (\n request.nextUrl.pathname === authConfigWithDefaults.loginUrl &&\n request.method === \"GET\"\n ) {\n console.log(\"→ Skipping auth check - this is the login URL\");\n return undefined;\n }\n\n if (!matchesGlobs(request.nextUrl.pathname, authConfigWithDefaults.include)) {\n console.log(\"→ Skipping auth check - path not in include patterns\");\n return undefined;\n }\n\n if (matchesGlobs(request.nextUrl.pathname, authConfigWithDefaults.exclude)) {\n console.log(\"→ Skipping auth check - path in exclude patterns\");\n return undefined;\n }\n\n // Check for either token type\n if (!isAuthenticated) {\n const loginUrl = new URL(authConfigWithDefaults.loginUrl, request.url);\n console.log(\"→ No valid token found - redirecting to login\", loginUrl);\n return NextResponse.redirect(loginUrl);\n }\n\n console.log(\"→ Auth check passed\");\n return undefined;\n};\n\n/**\n *\n * Use this when auth is the only middleware you need.\n * Usage:\n *\n * export default authMiddleware({ loginUrl = '/login' }); // or just authMiddleware();\n *\n */\nexport const authMiddleware =\n (authConfig = defaultAuthConfig) =>\n async (request: NextRequest): Promise<NextResponse> => {\n const response = await applyAuth(authConfig, request);\n if (response) return response;\n\n // NextJS doesn't do middleware chaining yet, so this does not mean\n // \"call the next middleware\" - it means \"continue to the route handler\"\n return NextResponse.next();\n };\n\n/**\n * Usage:\n *\n * export default withAuth(async (request) => {\n * console.log('my middleware');\n * return NextResponse.next();\n * })\n */\n// use this when you have your own middleware to chain\nexport function withAuth(\n middleware: Middleware,\n): (request: NextRequest) => Promise<NextResponse> {\n return async (request: NextRequest): Promise<NextResponse> => {\n const response = await applyAuth({}, request);\n if (response) return response;\n\n return middleware(request);\n };\n}\n\n/**\n * Use this when you want to configure the middleware here (an alternative is to do it in the next.config file)\n *\n * Usage:\n *\n * const withAuth = auth({ loginUrl = '/login' }); // or just auth();\n *\n * export default withAuth(async (request) => {\n * console.log('my middleware');\n * return NextResponse.next();\n * })\n *\n */\nexport function auth(authConfig: AuthConfig = {}) {\n return (\n middleware: Middleware,\n ): ((request: NextRequest) => Promise<NextResponse>) => {\n return async (request: NextRequest): Promise<NextResponse> => {\n const response = await applyAuth(authConfig, request);\n if (response) return response;\n\n return middleware(request);\n };\n };\n}\n","import { NextRequest, NextResponse } from \"next/server.js\";\nimport { revalidatePath } from \"next/cache.js\";\nimport { AuthConfig, resolveAuthConfig } from \"@/nextjs/config.js\";\nimport { loggers } from \"@/lib/logger.js\";\nimport {\n clearAuthCookies,\n NextjsClientStorage,\n NextjsCookieStorage,\n} from \"@/nextjs/cookies.js\";\nimport { GenericPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport { resolveOAuthAccessCode } from \"@/server/login.js\";\nimport { getUser } from \"@/shared/session.js\";\nimport { resolveCallbackUrl } from \"@/nextjs/utils.js\";\nimport { GenericUserSession } from \"@/shared/UserSession.js\";\nimport {\n TOKEN_EXCHANGE_SUCCESS_TEXT,\n TOKEN_EXCHANGE_TRIGGER_TEXT,\n} from \"@/constants.js\";\nimport { serverTokenExchangeFromState } from \"@/lib/oauth.js\";\nimport { cookies } from \"next/headers.js\";\nimport { CodeVerifier } from \"@/shared/types\";\n\nconst logger = loggers.nextjs.handlers.auth;\n\nclass AuthError extends Error {\n constructor(\n message: string,\n public readonly status: number = 401,\n ) {\n super(message);\n this.name = \"AuthError\";\n }\n}\n\n/**\n * create a code verifier and challenge for PKCE\n * saving the verifier in a cookie for later use\n * @returns {Promise<NextResponse>}\n */\nasync function handleChallenge(config: AuthConfig): Promise<NextResponse> {\n const cookieStorage = new NextjsCookieStorage(config.cookies?.tokens ?? {});\n const pkceProducer = new GenericPublicClientPKCEProducer(cookieStorage);\n\n const challenge = await pkceProducer.getCodeChallenge();\n\n return NextResponse.json({ status: \"success\", challenge });\n}\n\nasync function performTokenExchangeAndSetCookies(\n request: NextRequest,\n config: AuthConfig,\n code: string,\n state: string,\n) {\n const resolvedConfigs = resolveAuthConfig(config);\n const cookieStorage = new NextjsCookieStorage(resolvedConfigs.cookies.tokens);\n\n const callbackUrl = resolveCallbackUrl(resolvedConfigs, request.url);\n try {\n await resolveOAuthAccessCode(code, state, cookieStorage, {\n ...resolvedConfigs,\n redirectUrl: callbackUrl,\n });\n } catch (error) {\n logger.error(\"Token exchange failed:\", error);\n throw new AuthError(\"Failed to authenticate user\", 401);\n }\n\n const user = await getUser(cookieStorage);\n if (!user) {\n throw new AuthError(\"Failed to get user info\", 401);\n }\n\n const clientStorage = new NextjsClientStorage();\n const userSession = new GenericUserSession(clientStorage);\n userSession.set(user);\n}\nasync function handleCallback(\n request: NextRequest,\n config: AuthConfig,\n): Promise<NextResponse> {\n const resolvedConfigs = resolveAuthConfig(config);\n console.log(\"handleCallback\", { request, resolvedConfigs });\n const code = request.nextUrl.searchParams.get(\"code\");\n const state = request.nextUrl.searchParams.get(\"state\") || \"\";\n if (!code || !state) throw new AuthError(\"Bad parameters\", 400);\n\n // If we have a code_verifier cookie, we can do a token exchange.\n // Otherwise, just render an empty page.\n // The initial redirect back from the auth server does not send cookies, because the redirect is from a 3rd-party domain.\n // The client will make an additional call to this route with cookies included, at which point we do the token exchange.\n console.log(\"handleCallback\", { code, state, cookies: cookies() });\n if (!request.cookies.get(CodeVerifier.COOKIE_NAME)) {\n console.log(\"handleCallback no code_verifier found\", {\n state,\n serverTokenExchange: serverTokenExchangeFromState(`${state}`),\n });\n let response = new NextResponse(\n `<html><body><span style=\"display:none\">${TOKEN_EXCHANGE_TRIGGER_TEXT}</span></body></html>`,\n );\n // in server-side token exchange mode we need to launch a page that will trigger the token exchange\n // from the same domain, allowing it access to the code_verifier cookie\n // we only need to do this in redirect mode, as the iframe already triggers a client-side token exchange\n // if no code-verifier cookie is found\n if (state && serverTokenExchangeFromState(state)) {\n console.log(\n \"handleCallback serverTokenExchangeFromState, launching redirect page...\",\n {\n requestUrl: request.url,\n configCallbackUrl: resolvedConfigs.callbackUrl,\n },\n );\n // we need to replace the URL with resolved config in case the server is hosted\n // behind a reverse proxy or load balancer\n const requestUrl = new URL(request.url);\n const fetchUrl = `${resolvedConfigs.callbackUrl}?${requestUrl.searchParams.toString()}&sameDomainServerTokenExchange=true`;\n response = new NextResponse(\n `<html>\n <body>\n <span style=\"display:none\">\n <script>\n window.onload = function () {\n fetch('${fetchUrl}').then((response) => {\n response.json().then((jsonResponse) => {\n console.log('fetch jsonResponse', jsonResponse);\n if (jsonResponse.redirectUrl) {\n console.log('handleCallback serverTokenExchangeFromState, redirecting');\n window.location.href = jsonResponse.redirectUrl;\n }\n });\n });\n };\n </script>\n </span>\n </body>\n </html>\n `,\n );\n }\n response.headers.set(\"Content-Type\", \"text/html; charset=utf-8\");\n console.log(\n `handleCallback no code_verifier found, returning ${TOKEN_EXCHANGE_TRIGGER_TEXT}`,\n );\n return response;\n }\n\n await performTokenExchangeAndSetCookies(\n request,\n resolvedConfigs,\n code,\n state,\n );\n\n if (request.url.includes(\"sameDomainServerTokenExchange=true\")) {\n console.log(\n \"handleCallback sameDomainServerTokenExchange = true, returnining redirectUrl\",\n resolvedConfigs.appUrl,\n );\n return NextResponse.json({\n status: \"success\",\n redirectUrl: resolvedConfigs.appUrl,\n });\n }\n\n // this is the case where a 'normal' redirect is happening\n if (serverTokenExchangeFromState(state)) {\n console.log(\n \"handleCallback serverTokenExchangeFromState, redirect to config.appUrl\",\n resolvedConfigs.appUrl,\n );\n if (!resolvedConfigs.appUrl) {\n throw new Error(\"appUrl not defined in config. Cannot redirect.\");\n }\n return NextResponse.redirect(`${resolvedConfigs.appUrl}`);\n }\n // return an empty HTML response so the iframe doesn't show any response\n // in the short moment between the redirect and the parent window\n // acknowledging the redirect and closing the iframe\n const response = new NextResponse(\n `<html><span style=\"display:none\">${TOKEN_EXCHANGE_SUCCESS_TEXT}</span></html>`,\n );\n response.headers.set(\"Content-Type\", \"text/html; charset=utf-8\");\n return response;\n}\n\n/**\n * If redirectPath is an absolute path, return it as-is.\n * Otherwise for relative paths, append it to the current domain.\n * @param redirectPath\n * @returns\n */\nconst getAbsoluteRedirectPath = (\n redirectPath: string,\n currentBasePath: string,\n) => {\n // Check if the redirectPath is an absolute URL\n if (/^(https?:\\/\\/|www\\.).+/i.test(redirectPath)) {\n return redirectPath; // Return as-is if it's an absolute URL\n }\n return new URL(redirectPath, currentBasePath).href;\n};\n\nexport async function handleLogout(\n request: NextRequest,\n config: AuthConfig,\n): Promise<NextResponse> {\n const resolvedConfigs = resolveAuthConfig(config);\n const defaultRedirectPath = resolvedConfigs.loginUrl ?? \"/\";\n const redirectTarget =\n new URL(request.url).searchParams.get(\"redirect\") || defaultRedirectPath;\n const isAbsoluteRedirect = /^(https?:\\/\\/|www\\.).+/i.test(redirectTarget);\n const finalRedirectUrl = getAbsoluteRedirectPath(\n redirectTarget,\n new URL(resolvedConfigs.appUrl ?? request.url).origin,\n );\n\n const response = NextResponse.redirect(finalRedirectUrl);\n\n clearAuthCookies(config);\n\n try {\n revalidatePath(isAbsoluteRedirect ? finalRedirectUrl : redirectTarget);\n } catch (error) {\n logger.warn(\"Failed to revalidate path after logout:\", error);\n }\n\n return response;\n}\n\n/**\n * Creates an authentication handler for Next.js API routes\n *\n * Usage:\n * ```ts\n * // app/api/auth/[...civicauth]/route.ts\n * import { handler } from '@civic/auth/nextjs'\n * export const GET = handler({\n * // optional config overrides\n * })\n * ```\n */\nexport const handler =\n (authConfig = {}) =>\n async (request: NextRequest): Promise<NextResponse> => {\n const config = resolveAuthConfig(authConfig);\n\n try {\n const pathname = request.nextUrl.pathname;\n const pathSegments = pathname.split(\"/\");\n const lastSegment = pathSegments[pathSegments.length - 1];\n\n switch (lastSegment) {\n case \"challenge\":\n return await handleChallenge(config);\n case \"callback\":\n return await handleCallback(request, config);\n case \"logout\":\n return await handleLogout(request, config);\n default:\n throw new AuthError(`Invalid auth route: ${pathname}`, 404);\n }\n } catch (error) {\n logger.error(\"Auth handler error:\", error);\n\n const status = error instanceof AuthError ? error.status : 500;\n const message =\n error instanceof Error ? error.message : \"Authentication failed\";\n\n const response = NextResponse.json({ error: message }, { status });\n\n clearAuthCookies(config);\n return response;\n }\n };\n"]}
|
package/dist/nextjs.mjs
CHANGED
|
@@ -2,20 +2,28 @@ import {
|
|
|
2
2
|
NextjsClientStorage,
|
|
3
3
|
NextjsCookieStorage,
|
|
4
4
|
clearAuthCookies,
|
|
5
|
+
createTokenCookies,
|
|
6
|
+
createUserInfoCookie,
|
|
7
|
+
resolveCallbackUrl
|
|
8
|
+
} from "./chunk-BFESCRFK.mjs";
|
|
9
|
+
import {
|
|
5
10
|
createCivicAuthPlugin,
|
|
6
11
|
defaultAuthConfig,
|
|
7
12
|
loggers,
|
|
8
|
-
resolveAuthConfig
|
|
9
|
-
|
|
10
|
-
|
|
13
|
+
resolveAuthConfig
|
|
14
|
+
} from "./chunk-X3FQBE22.mjs";
|
|
15
|
+
import {
|
|
16
|
+
resolveOAuthAccessCode
|
|
17
|
+
} from "./chunk-HTTTZ2BP.mjs";
|
|
11
18
|
import {
|
|
12
19
|
GenericPublicClientPKCEProducer,
|
|
13
20
|
GenericUserSession,
|
|
21
|
+
TOKEN_EXCHANGE_SUCCESS_TEXT,
|
|
14
22
|
TOKEN_EXCHANGE_TRIGGER_TEXT,
|
|
15
23
|
getUser,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
} from "./chunk-
|
|
24
|
+
retrieveTokens,
|
|
25
|
+
serverTokenExchangeFromState
|
|
26
|
+
} from "./chunk-CBQ3HKRV.mjs";
|
|
19
27
|
import {
|
|
20
28
|
__async,
|
|
21
29
|
__spreadProps,
|
|
@@ -69,8 +77,8 @@ var applyAuth = (authConfig, request) => __async(void 0, null, function* () {
|
|
|
69
77
|
return void 0;
|
|
70
78
|
}
|
|
71
79
|
if (!isAuthenticated) {
|
|
72
|
-
console.log("\u2192 No valid token found - redirecting to login");
|
|
73
80
|
const loginUrl = new URL(authConfigWithDefaults.loginUrl, request.url);
|
|
81
|
+
console.log("\u2192 No valid token found - redirecting to login", loginUrl);
|
|
74
82
|
return NextResponse.redirect(loginUrl);
|
|
75
83
|
}
|
|
76
84
|
console.log("\u2192 Auth check passed");
|
|
@@ -101,6 +109,7 @@ function auth(authConfig = {}) {
|
|
|
101
109
|
// src/nextjs/routeHandler.ts
|
|
102
110
|
import { NextResponse as NextResponse2 } from "next/server.js";
|
|
103
111
|
import { revalidatePath } from "next/cache.js";
|
|
112
|
+
import { cookies } from "next/headers.js";
|
|
104
113
|
var logger = loggers.nextjs.handlers.auth;
|
|
105
114
|
var AuthError = class extends Error {
|
|
106
115
|
constructor(message, status = 401) {
|
|
@@ -109,29 +118,17 @@ var AuthError = class extends Error {
|
|
|
109
118
|
this.name = "AuthError";
|
|
110
119
|
}
|
|
111
120
|
};
|
|
112
|
-
function handleChallenge() {
|
|
121
|
+
function handleChallenge(config) {
|
|
113
122
|
return __async(this, null, function* () {
|
|
114
|
-
|
|
123
|
+
var _a, _b;
|
|
124
|
+
const cookieStorage = new NextjsCookieStorage((_b = (_a = config.cookies) == null ? void 0 : _a.tokens) != null ? _b : {});
|
|
115
125
|
const pkceProducer = new GenericPublicClientPKCEProducer(cookieStorage);
|
|
116
126
|
const challenge = yield pkceProducer.getCodeChallenge();
|
|
117
127
|
return NextResponse2.json({ status: "success", challenge });
|
|
118
128
|
});
|
|
119
129
|
}
|
|
120
|
-
function
|
|
130
|
+
function performTokenExchangeAndSetCookies(request, config, code, state) {
|
|
121
131
|
return __async(this, null, function* () {
|
|
122
|
-
if (!request.cookies.get("code_verifier")) {
|
|
123
|
-
const response2 = new NextResponse2(
|
|
124
|
-
`<html><body><span style="display:none">${TOKEN_EXCHANGE_TRIGGER_TEXT}</span></body></html>`
|
|
125
|
-
);
|
|
126
|
-
response2.headers.set("Content-Type", "text/html; charset=utf-8");
|
|
127
|
-
console.log(
|
|
128
|
-
`handleCallback no code_verifier found, returning ${TOKEN_EXCHANGE_TRIGGER_TEXT}`
|
|
129
|
-
);
|
|
130
|
-
return response2;
|
|
131
|
-
}
|
|
132
|
-
const code = request.nextUrl.searchParams.get("code");
|
|
133
|
-
const state = request.nextUrl.searchParams.get("state");
|
|
134
|
-
if (!code || !state) throw new AuthError("Bad parameters", 400);
|
|
135
132
|
const resolvedConfigs = resolveAuthConfig(config);
|
|
136
133
|
const cookieStorage = new NextjsCookieStorage(resolvedConfigs.cookies.tokens);
|
|
137
134
|
const callbackUrl = resolveCallbackUrl(resolvedConfigs, request.url);
|
|
@@ -150,7 +147,92 @@ function handleCallback(request, config) {
|
|
|
150
147
|
const clientStorage = new NextjsClientStorage();
|
|
151
148
|
const userSession = new GenericUserSession(clientStorage);
|
|
152
149
|
userSession.set(user);
|
|
153
|
-
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
function handleCallback(request, config) {
|
|
153
|
+
return __async(this, null, function* () {
|
|
154
|
+
const resolvedConfigs = resolveAuthConfig(config);
|
|
155
|
+
console.log("handleCallback", { request, resolvedConfigs });
|
|
156
|
+
const code = request.nextUrl.searchParams.get("code");
|
|
157
|
+
const state = request.nextUrl.searchParams.get("state") || "";
|
|
158
|
+
if (!code || !state) throw new AuthError("Bad parameters", 400);
|
|
159
|
+
console.log("handleCallback", { code, state, cookies: cookies() });
|
|
160
|
+
if (!request.cookies.get("code_verifier" /* COOKIE_NAME */)) {
|
|
161
|
+
console.log("handleCallback no code_verifier found", {
|
|
162
|
+
state,
|
|
163
|
+
serverTokenExchange: serverTokenExchangeFromState(`${state}`)
|
|
164
|
+
});
|
|
165
|
+
let response2 = new NextResponse2(
|
|
166
|
+
`<html><body><span style="display:none">${TOKEN_EXCHANGE_TRIGGER_TEXT}</span></body></html>`
|
|
167
|
+
);
|
|
168
|
+
if (state && serverTokenExchangeFromState(state)) {
|
|
169
|
+
console.log(
|
|
170
|
+
"handleCallback serverTokenExchangeFromState, launching redirect page...",
|
|
171
|
+
{
|
|
172
|
+
requestUrl: request.url,
|
|
173
|
+
configCallbackUrl: resolvedConfigs.callbackUrl
|
|
174
|
+
}
|
|
175
|
+
);
|
|
176
|
+
const requestUrl = new URL(request.url);
|
|
177
|
+
const fetchUrl = `${resolvedConfigs.callbackUrl}?${requestUrl.searchParams.toString()}&sameDomainServerTokenExchange=true`;
|
|
178
|
+
response2 = new NextResponse2(
|
|
179
|
+
`<html>
|
|
180
|
+
<body>
|
|
181
|
+
<span style="display:none">
|
|
182
|
+
<script>
|
|
183
|
+
window.onload = function () {
|
|
184
|
+
fetch('${fetchUrl}').then((response) => {
|
|
185
|
+
response.json().then((jsonResponse) => {
|
|
186
|
+
console.log('fetch jsonResponse', jsonResponse);
|
|
187
|
+
if (jsonResponse.redirectUrl) {
|
|
188
|
+
console.log('handleCallback serverTokenExchangeFromState, redirecting');
|
|
189
|
+
window.location.href = jsonResponse.redirectUrl;
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
};
|
|
194
|
+
</script>
|
|
195
|
+
</span>
|
|
196
|
+
</body>
|
|
197
|
+
</html>
|
|
198
|
+
`
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
response2.headers.set("Content-Type", "text/html; charset=utf-8");
|
|
202
|
+
console.log(
|
|
203
|
+
`handleCallback no code_verifier found, returning ${TOKEN_EXCHANGE_TRIGGER_TEXT}`
|
|
204
|
+
);
|
|
205
|
+
return response2;
|
|
206
|
+
}
|
|
207
|
+
yield performTokenExchangeAndSetCookies(
|
|
208
|
+
request,
|
|
209
|
+
resolvedConfigs,
|
|
210
|
+
code,
|
|
211
|
+
state
|
|
212
|
+
);
|
|
213
|
+
if (request.url.includes("sameDomainServerTokenExchange=true")) {
|
|
214
|
+
console.log(
|
|
215
|
+
"handleCallback sameDomainServerTokenExchange = true, returnining redirectUrl",
|
|
216
|
+
resolvedConfigs.appUrl
|
|
217
|
+
);
|
|
218
|
+
return NextResponse2.json({
|
|
219
|
+
status: "success",
|
|
220
|
+
redirectUrl: resolvedConfigs.appUrl
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
if (serverTokenExchangeFromState(state)) {
|
|
224
|
+
console.log(
|
|
225
|
+
"handleCallback serverTokenExchangeFromState, redirect to config.appUrl",
|
|
226
|
+
resolvedConfigs.appUrl
|
|
227
|
+
);
|
|
228
|
+
if (!resolvedConfigs.appUrl) {
|
|
229
|
+
throw new Error("appUrl not defined in config. Cannot redirect.");
|
|
230
|
+
}
|
|
231
|
+
return NextResponse2.redirect(`${resolvedConfigs.appUrl}`);
|
|
232
|
+
}
|
|
233
|
+
const response = new NextResponse2(
|
|
234
|
+
`<html><span style="display:none">${TOKEN_EXCHANGE_SUCCESS_TEXT}</span></html>`
|
|
235
|
+
);
|
|
154
236
|
response.headers.set("Content-Type", "text/html; charset=utf-8");
|
|
155
237
|
return response;
|
|
156
238
|
});
|
|
@@ -163,17 +245,17 @@ var getAbsoluteRedirectPath = (redirectPath, currentBasePath) => {
|
|
|
163
245
|
};
|
|
164
246
|
function handleLogout(request, config) {
|
|
165
247
|
return __async(this, null, function* () {
|
|
166
|
-
var _a;
|
|
248
|
+
var _a, _b;
|
|
167
249
|
const resolvedConfigs = resolveAuthConfig(config);
|
|
168
250
|
const defaultRedirectPath = (_a = resolvedConfigs.loginUrl) != null ? _a : "/";
|
|
169
251
|
const redirectTarget = new URL(request.url).searchParams.get("redirect") || defaultRedirectPath;
|
|
170
252
|
const isAbsoluteRedirect = /^(https?:\/\/|www\.).+/i.test(redirectTarget);
|
|
171
253
|
const finalRedirectUrl = getAbsoluteRedirectPath(
|
|
172
254
|
redirectTarget,
|
|
173
|
-
new URL(request.url).origin
|
|
255
|
+
new URL((_b = resolvedConfigs.appUrl) != null ? _b : request.url).origin
|
|
174
256
|
);
|
|
175
257
|
const response = NextResponse2.redirect(finalRedirectUrl);
|
|
176
|
-
clearAuthCookies();
|
|
258
|
+
clearAuthCookies(config);
|
|
177
259
|
try {
|
|
178
260
|
revalidatePath(isAbsoluteRedirect ? finalRedirectUrl : redirectTarget);
|
|
179
261
|
} catch (error) {
|
|
@@ -190,7 +272,7 @@ var handler = (authConfig = {}) => (request) => __async(void 0, null, function*
|
|
|
190
272
|
const lastSegment = pathSegments[pathSegments.length - 1];
|
|
191
273
|
switch (lastSegment) {
|
|
192
274
|
case "challenge":
|
|
193
|
-
return yield handleChallenge();
|
|
275
|
+
return yield handleChallenge(config);
|
|
194
276
|
case "callback":
|
|
195
277
|
return yield handleCallback(request, config);
|
|
196
278
|
case "logout":
|
|
@@ -203,14 +285,19 @@ var handler = (authConfig = {}) => (request) => __async(void 0, null, function*
|
|
|
203
285
|
const status = error instanceof AuthError ? error.status : 500;
|
|
204
286
|
const message = error instanceof Error ? error.message : "Authentication failed";
|
|
205
287
|
const response = NextResponse2.json({ error: message }, { status });
|
|
206
|
-
clearAuthCookies();
|
|
288
|
+
clearAuthCookies(config);
|
|
207
289
|
return response;
|
|
208
290
|
}
|
|
209
291
|
});
|
|
210
292
|
export {
|
|
293
|
+
NextjsClientStorage,
|
|
294
|
+
NextjsCookieStorage,
|
|
211
295
|
auth,
|
|
212
296
|
authMiddleware,
|
|
297
|
+
clearAuthCookies,
|
|
213
298
|
createCivicAuthPlugin,
|
|
299
|
+
createTokenCookies,
|
|
300
|
+
createUserInfoCookie,
|
|
214
301
|
getUser2 as getUser,
|
|
215
302
|
handler,
|
|
216
303
|
withAuth
|