@nekm/sveltekit-armor 0.4.1 → 0.5.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/dist/index.js CHANGED
@@ -1,33 +1,106 @@
1
- var kit = require('@sveltejs/kit');
2
- var core = require('@nekm/core');
3
- var jose = require('jose');
4
- var node_crypto = require('node:crypto');
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __defProps = Object.defineProperties;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
10
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
11
+ var __spreadValues = (a, b) => {
12
+ for (var prop in b || (b = {}))
13
+ if (__hasOwnProp.call(b, prop))
14
+ __defNormalProp(a, prop, b[prop]);
15
+ if (__getOwnPropSymbols)
16
+ for (var prop of __getOwnPropSymbols(b)) {
17
+ if (__propIsEnum.call(b, prop))
18
+ __defNormalProp(a, prop, b[prop]);
19
+ }
20
+ return a;
21
+ };
22
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
23
+ var __export = (target, all) => {
24
+ for (var name in all)
25
+ __defProp(target, name, { get: all[name], enumerable: true });
26
+ };
27
+ var __copyProps = (to, from, except, desc) => {
28
+ if (from && typeof from === "object" || typeof from === "function") {
29
+ for (let key of __getOwnPropNames(from))
30
+ if (!__hasOwnProp.call(to, key) && key !== except)
31
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
32
+ }
33
+ return to;
34
+ };
35
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
36
+ var __async = (__this, __arguments, generator) => {
37
+ return new Promise((resolve, reject) => {
38
+ var fulfilled = (value) => {
39
+ try {
40
+ step(generator.next(value));
41
+ } catch (e) {
42
+ reject(e);
43
+ }
44
+ };
45
+ var rejected = (value) => {
46
+ try {
47
+ step(generator.throw(value));
48
+ } catch (e) {
49
+ reject(e);
50
+ }
51
+ };
52
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
53
+ step((generator = generator.apply(__this, __arguments)).next());
54
+ });
55
+ };
5
56
 
57
+ // src/index.ts
58
+ var src_exports = {};
59
+ __export(src_exports, {
60
+ armor: () => armor,
61
+ armorConfigFromOpenId: () => armorConfigFromOpenId,
62
+ armorCookieSession: () => armorCookieSession,
63
+ armorCookieSessionGet: () => armorCookieSessionGet,
64
+ armorRefreshFactory: () => armorRefreshFactory
65
+ });
66
+ module.exports = __toCommonJS(src_exports);
67
+ var import_kit6 = require("@sveltejs/kit");
68
+
69
+ // src/routes/login.ts
70
+ var import_kit2 = require("@sveltejs/kit");
71
+ var import_core4 = require("@nekm/core");
72
+
73
+ // src/routes/redirect-login.ts
74
+ var import_kit = require("@sveltejs/kit");
75
+ var import_core3 = require("@nekm/core");
76
+ var import_jose2 = require("jose");
77
+
78
+ // src/utils/utils.ts
79
+ var import_core = require("@nekm/core");
6
80
  function urlConcat(origin, path) {
7
- return [core.strTrimEnd(origin, "/"), core.strTrimStart(path, "/")].join("/");
81
+ return [(0, import_core.strTrimEnd)(origin, "/"), (0, import_core.strTrimStart)(path, "/")].join("/");
8
82
  }
9
83
  function isTokenExchange(value) {
10
84
  if (typeof value !== "object" || value === null) return false;
11
85
  const obj = value;
12
- return typeof obj.access_token === "string" && obj.token_type === "Bearer" && typeof obj.expires_in === "number" && (
13
- // Optional fields
14
- typeof obj.id_token === "string" || obj.id_token === undefined) && (typeof obj.refresh_token === "string" || obj.refresh_token === undefined) && (typeof obj.scope === "string" || obj.scope === undefined);
86
+ return typeof obj.access_token === "string" && obj.token_type === "Bearer" && typeof obj.expires_in === "number" && // Optional fields
87
+ (typeof obj.id_token === "string" || obj.id_token === void 0) && (typeof obj.refresh_token === "string" || obj.refresh_token === void 0) && (typeof obj.scope === "string" || obj.scope === void 0);
15
88
  }
16
- const MINUTES_MS = 60 * 1000;
89
+ var MINUTES_MS = 60 * 1e3;
17
90
  function shouldRefresh(tokens) {
18
- const idExpiry = tokens.idToken.exp * 1000;
19
- const accessExpiry = typeof tokens.accessToken !== "string" && tokens.accessToken.exp !== undefined ? tokens.accessToken.exp * 1000 : Infinity;
91
+ const idExpiry = tokens.idToken.exp * 1e3;
92
+ const accessExpiry = typeof tokens.accessToken !== "string" && tokens.accessToken.exp !== void 0 ? tokens.accessToken.exp * 1e3 : Infinity;
20
93
  return Math.min(idExpiry, accessExpiry) < Date.now() + 5 * MINUTES_MS;
21
94
  }
22
95
  function createExpiresAt(seconds) {
23
- const now = new Date();
96
+ const now = /* @__PURE__ */ new Date();
24
97
  now.setSeconds(now.getSeconds() + seconds);
25
98
  return now;
26
99
  }
27
100
  function exchangeToTokens(exchange, idToken, accessToken) {
28
101
  return {
29
102
  exchange,
30
- idToken: idToken,
103
+ idToken,
31
104
  // Generally, IdP's require an audience to get a JWT
32
105
  // access token. Most cases, this doesn't matter.
33
106
  accessToken: accessToken != null ? accessToken : exchange.access_token,
@@ -35,61 +108,65 @@ function exchangeToTokens(exchange, idToken, accessToken) {
35
108
  };
36
109
  }
37
110
 
111
+ // src/utils/jwt.ts
112
+ var import_jose = require("jose");
113
+ var import_core2 = require("@nekm/core");
38
114
  function jwtIsCompactJwt(token) {
39
- // Must be three base64url segments
40
115
  const parts = token.trim().split(".");
41
- return parts.length === 3 && parts.every(p => p.length > 0);
116
+ return parts.length === 3 && parts.every((p) => p.length > 0);
42
117
  }
43
118
  function jwtVerifyIdToken(config, jwks, idToken) {
44
- const payload = jwtVerifyToken(jwks, {
45
- issuer: config.oauth.issuer,
46
- audience: config.oauth.clientId
47
- }, idToken);
48
- core.throwIfUndefined(payload);
49
- // @ts-expect-error We're already verifying non-null above.
119
+ const payload = jwtVerifyToken(
120
+ jwks,
121
+ {
122
+ issuer: config.oauth.issuer,
123
+ audience: config.oauth.clientId
124
+ },
125
+ idToken
126
+ );
127
+ (0, import_core2.throwIfUndefined)(payload);
50
128
  return payload;
51
129
  }
52
130
  function jwtVerifyAccessToken(config, jwks, accessToken) {
53
- const opts = {
54
- issuer: config.oauth.issuer
55
- };
131
+ const opts = { issuer: config.oauth.issuer };
56
132
  if (config.oauth.audience) {
57
133
  opts.audience = config.oauth.audience;
58
134
  }
59
135
  return jwtVerifyToken(jwks, opts, accessToken);
60
136
  }
61
137
  function isInvalidCompactJwt(error) {
62
- return Boolean(typeof error === "object" && error && "message" in error && typeof error.message === "string" && /invalid compact jws/gi.test(error.message));
138
+ return Boolean(
139
+ typeof error === "object" && error && "message" in error && typeof error.message === "string" && /invalid compact jws/gi.test(error.message)
140
+ );
63
141
  }
64
- async function jwtVerifyToken(jwks, opts, token) {
65
- try {
66
- if (!jwtIsCompactJwt(token)) {
67
- return undefined;
68
- }
69
- const {
70
- payload
71
- } = await jose.jwtVerify(token, jwks, opts);
72
- return payload;
73
- } catch (error) {
74
- if (isInvalidCompactJwt(error)) {
75
- return undefined;
142
+ function jwtVerifyToken(jwks, opts, token) {
143
+ return __async(this, null, function* () {
144
+ try {
145
+ if (!jwtIsCompactJwt(token)) {
146
+ return void 0;
147
+ }
148
+ const { payload } = yield (0, import_jose.jwtVerify)(token, jwks, opts);
149
+ return payload;
150
+ } catch (error) {
151
+ if (isInvalidCompactJwt(error)) {
152
+ return void 0;
153
+ }
154
+ throw error;
76
155
  }
77
- throw error;
78
- }
156
+ });
79
157
  }
80
158
 
81
- const COOKIE_TOKENS = "tokens";
82
- const COOKIE_STATE = "state";
83
- const cookieDeleteOptions = Object.freeze({
84
- path: "/"
85
- });
86
- const cookieSetOptions = Object.freeze({
87
- ...cookieDeleteOptions,
159
+ // src/utils/cookie.ts
160
+ var COOKIE_TOKENS = "tokens";
161
+ var COOKIE_STATE = "state";
162
+ var cookieDeleteOptions = Object.freeze({ path: "/" });
163
+ var cookieSetOptions = Object.freeze(__spreadProps(__spreadValues({}, cookieDeleteOptions), {
88
164
  httpOnly: true,
89
165
  secure: true,
90
166
  sameSite: "lax",
91
- maxAge: 1800 // 30 minutes
92
- });
167
+ maxAge: 1800
168
+ // 30 minutes
169
+ }));
93
170
  function cookieSet(cookies, key, value) {
94
171
  cookies.set(key, JSON.stringify(value), cookieSetOptions);
95
172
  }
@@ -102,207 +179,239 @@ function cookieGetAndDelete(cookies, key) {
102
179
  }
103
180
  function cookieGet(cookies, key) {
104
181
  const value = cookies.get(key);
105
- return !value ? undefined : JSON.parse(value);
182
+ return !value ? void 0 : JSON.parse(value);
106
183
  }
107
184
  function cookieDelete(cookies, key) {
108
185
  cookies.delete(key, cookieDeleteOptions);
109
186
  }
110
187
 
111
- class ArmorError extends Error {}
112
- class ArmorOpenIdConfigError extends ArmorError {}
113
- class ArmorInvalidStateError extends ArmorError {}
114
- class ArmorAuthMissingError extends ArmorError {}
115
- class ArmorRefreshError extends ArmorError {}
116
-
117
- function eventStateValidOrThrow(event) {
118
- var _event$url$searchPara;
119
- const state = (_event$url$searchPara = event.url.searchParams.get("state")) != null ? _event$url$searchPara : undefined;
188
+ // src/utils/event.ts
189
+ function eventStateValid(event) {
190
+ var _a;
191
+ const state = (_a = event.url.searchParams.get("state")) != null ? _a : void 0;
120
192
  const stateCookie = cookieGetAndDelete(event.cookies, COOKIE_STATE);
121
- if (state !== stateCookie) {
122
- throw new ArmorInvalidStateError();
123
- }
193
+ return state !== stateCookie;
124
194
  }
125
195
 
126
- const ROUTE_PATH_REDIRECT_LOGIN = "/_armor/redirect/login";
127
- const routeRedirectLoginFactory = config => {
128
- var _config$oauth$jwksEnd, _config$oauth$tokenEn, _config$oauth$scope;
129
- const jwksUrl = new URL((_config$oauth$jwksEnd = config.oauth.jwksEndpoint) != null ? _config$oauth$jwksEnd : urlConcat(config.oauth.baseUrl, ".well-known/jwks.json"));
130
- const tokenUrl = (_config$oauth$tokenEn = config.oauth.tokenEndpoint) != null ? _config$oauth$tokenEn : urlConcat(config.oauth.baseUrl, "oauth2/token");
131
- const scope = (_config$oauth$scope = config.oauth.scope) != null ? _config$oauth$scope : "openid profile email";
132
- async function exchangeCodeForToken(fetch, origin, code) {
133
- const params = {
134
- grant_type: "authorization_code",
135
- client_id: config.oauth.clientId,
136
- client_secret: config.oauth.clientSecret,
137
- code,
138
- redirect_uri: urlConcat(origin, ROUTE_PATH_REDIRECT_LOGIN),
139
- scope
140
- };
141
- if (config.oauth.audience) {
142
- params.audience = config.oauth.audience;
143
- }
144
- const response = await fetch(tokenUrl, {
145
- method: "POST",
146
- headers: {
147
- "Content-Type": "application/x-www-form-urlencoded",
148
- Accept: "application/json"
149
- },
150
- body: new URLSearchParams(params).toString()
196
+ // src/routes/redirect-login.ts
197
+ var ROUTE_PATH_REDIRECT_LOGIN = "/_armor/redirect/login";
198
+ var routeRedirectLoginFactory = (config) => {
199
+ var _a, _b, _c;
200
+ const jwksUrl = new URL(
201
+ (_a = config.oauth.jwksEndpoint) != null ? _a : urlConcat(config.oauth.baseUrl, ".well-known/jwks.json")
202
+ );
203
+ const tokenUrl = (_b = config.oauth.tokenEndpoint) != null ? _b : urlConcat(config.oauth.baseUrl, "oauth2/token");
204
+ const scope = (_c = config.oauth.scope) != null ? _c : "openid profile email";
205
+ function exchangeCodeForToken(fetch2, origin, code) {
206
+ return __async(this, null, function* () {
207
+ const params = {
208
+ grant_type: "authorization_code",
209
+ client_id: config.oauth.clientId,
210
+ client_secret: config.oauth.clientSecret,
211
+ code,
212
+ redirect_uri: urlConcat(origin, ROUTE_PATH_REDIRECT_LOGIN),
213
+ scope
214
+ };
215
+ if (config.oauth.audience) {
216
+ params.audience = config.oauth.audience;
217
+ }
218
+ const response = yield fetch2(tokenUrl, {
219
+ method: "POST",
220
+ headers: {
221
+ "Content-Type": "application/x-www-form-urlencoded",
222
+ Accept: "application/json"
223
+ },
224
+ body: new URLSearchParams(params).toString()
225
+ });
226
+ if (!response.ok) {
227
+ const error = yield response.text();
228
+ throw new Error(`Token exchange failed: ${error}`);
229
+ }
230
+ const token = yield response.json();
231
+ if (!isTokenExchange(token)) {
232
+ throw new Error("Response is not a valid token exchange.");
233
+ }
234
+ return token;
151
235
  });
152
- if (!response.ok) {
153
- const error = await response.text();
154
- throw new Error(`Token exchange failed: ${error}`);
155
- }
156
- const token = await response.json();
157
- if (!isTokenExchange(token)) {
158
- throw new Error("Response is not a valid token exchange.");
159
- }
160
- return token;
161
236
  }
162
237
  return {
163
238
  path: ROUTE_PATH_REDIRECT_LOGIN,
164
- async handle({
165
- event
166
- }) {
167
- var _config$logger, _event$url$searchPara, _event$url$searchPara3, _config$logger3, _config$logger4, _config$logger5;
168
- (_config$logger = config.logger) == null || _config$logger.debug == null || _config$logger.debug("Handle login redirect callback.");
169
- eventStateValidOrThrow(event);
170
- const error = (_event$url$searchPara = event.url.searchParams.get("error")) != null ? _event$url$searchPara : undefined;
171
- if (error) {
172
- var _event$url$searchPara2, _config$logger2;
173
- const error_description = (_event$url$searchPara2 = event.url.searchParams.get("error_description")) != null ? _event$url$searchPara2 : undefined;
174
- (_config$logger2 = config.logger) == null || _config$logger2.error == null || _config$logger2.error("Login returned error.", {
175
- error,
176
- errorDescription: error_description
177
- });
178
- if (!config.oauth.errorLoginRedirectPath) {
179
- return new Response(`${error}\n${error_description}`.trimEnd(), {
180
- headers: {
181
- "Content-Type": "text/plain"
182
- }
239
+ handle(_0) {
240
+ return __async(this, arguments, function* ({ event }) {
241
+ var _a2, _b2, _c2, _d2, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
242
+ (_b2 = (_a2 = config.logger) == null ? void 0 : _a2.debug) == null ? void 0 : _b2.call(_a2, "Handle login redirect callback.");
243
+ if (!eventStateValid(event)) {
244
+ (_d2 = (_c2 = config.logger) == null ? void 0 : _c2.warning) == null ? void 0 : _d2.call(_c2, "State missmatch");
245
+ throw (0, import_kit.redirect)(302, ROUTE_PATH_LOGIN);
246
+ }
247
+ const error = (_e = event.url.searchParams.get("error")) != null ? _e : void 0;
248
+ if (error) {
249
+ const error_description = (_f = event.url.searchParams.get("error_description")) != null ? _f : void 0;
250
+ (_h = (_g = config.logger) == null ? void 0 : _g.error) == null ? void 0 : _h.call(_g, "Login returned error.", {
251
+ error,
252
+ errorDescription: error_description
183
253
  });
254
+ if (!config.oauth.errorLoginRedirectPath) {
255
+ return new Response(`${error}
256
+ ${error_description}`.trimEnd(), {
257
+ headers: {
258
+ "Content-Type": "text/plain"
259
+ }
260
+ });
261
+ }
262
+ const errorParams = (0, import_core3.queryParamsCreate)({ error, error_description });
263
+ throw (0, import_kit.redirect)(
264
+ 302,
265
+ `${config.oauth.errorLoginRedirectPath}?${errorParams}`
266
+ );
184
267
  }
185
- const errorParams = core.queryParamsCreate({
186
- error,
187
- error_description
268
+ const code = (_i = event.url.searchParams.get("code")) != null ? _i : void 0;
269
+ (_k = (_j = config.logger) == null ? void 0 : _j.debug) == null ? void 0 : _k.call(_j, "Get code from query params.", { code });
270
+ (0, import_core3.throwIfUndefined)(code);
271
+ const exchange = yield exchangeCodeForToken(
272
+ event.fetch,
273
+ event.url.origin,
274
+ code
275
+ );
276
+ (_m = (_l = config.logger) == null ? void 0 : _l.debug) == null ? void 0 : _m.call(_l, "Exchange code for tokens.", { exchange });
277
+ const jwks = (0, import_jose2.createRemoteJWKSet)(jwksUrl);
278
+ const [idToken, accessToken] = yield Promise.all([
279
+ jwtVerifyIdToken(config, jwks, exchange.id_token),
280
+ jwtVerifyAccessToken(config, jwks, exchange.access_token)
281
+ ]);
282
+ (_o = (_n = config.logger) == null ? void 0 : _n.debug) == null ? void 0 : _o.call(_n, "Extract and verify tokens.", {
283
+ idToken,
284
+ accessToken
188
285
  });
189
- throw kit.redirect(302, `${config.oauth.errorLoginRedirectPath}?${errorParams}`);
190
- }
191
- const code = (_event$url$searchPara3 = event.url.searchParams.get("code")) != null ? _event$url$searchPara3 : undefined;
192
- (_config$logger3 = config.logger) == null || _config$logger3.debug == null || _config$logger3.debug("Get code from query params.", {
193
- code
194
- });
195
- core.throwIfUndefined(code);
196
- const exchange = await exchangeCodeForToken(event.fetch, event.url.origin, code);
197
- (_config$logger4 = config.logger) == null || _config$logger4.debug == null || _config$logger4.debug("Exchange code for tokens.", {
198
- exchange
199
- });
200
- const jwks = jose.createRemoteJWKSet(jwksUrl);
201
- const [idToken, accessToken] = await Promise.all([jwtVerifyIdToken(config, jwks, exchange.id_token), jwtVerifyAccessToken(config, jwks, exchange.access_token)]);
202
- (_config$logger5 = config.logger) == null || _config$logger5.debug == null || _config$logger5.debug("Extract and verify tokens.", {
203
- idToken,
204
- accessToken
286
+ yield config.session.login(
287
+ event,
288
+ exchangeToTokens(exchange, idToken, accessToken)
289
+ );
290
+ throw (0, import_kit.redirect)(302, "/");
205
291
  });
206
- await config.session.login(event, exchangeToTokens(exchange, idToken, accessToken));
207
- throw kit.redirect(302, "/");
208
292
  }
209
293
  };
210
294
  };
211
295
 
212
- const ARMOR_LOGIN = "/_armor/login";
213
- const ARMOR_LOGOUT = "/_armor/logout";
296
+ // src/routes/login.ts
297
+ var import_node_crypto = require("crypto");
298
+
299
+ // src/browser/index.ts
300
+ var ARMOR_LOGIN = "/_armor/login";
301
+ var ARMOR_LOGOUT = "/_armor/logout";
214
302
 
215
- const ROUTE_PATH_LOGIN = ARMOR_LOGIN;
216
- const routeLoginFactory = config => {
217
- var _config$oauth$authori, _config$oauth$scope;
218
- const authorizeEndpoint = (_config$oauth$authori = config.oauth.authorizeEndpoint) != null ? _config$oauth$authori : urlConcat(config.oauth.baseUrl, "oauth2/authorize");
219
- const scope = (_config$oauth$scope = config.oauth.scope) != null ? _config$oauth$scope : "openid profile email";
303
+ // src/routes/login.ts
304
+ var ROUTE_PATH_LOGIN = ARMOR_LOGIN;
305
+ var routeLoginFactory = (config) => {
306
+ var _a, _b;
307
+ const authorizeEndpoint = (_a = config.oauth.authorizeEndpoint) != null ? _a : urlConcat(config.oauth.baseUrl, "oauth2/authorize");
308
+ const scope = (_b = config.oauth.scope) != null ? _b : "openid profile email";
220
309
  return {
221
310
  path: ROUTE_PATH_LOGIN,
222
- async handle({
223
- event
224
- }) {
225
- var _config$logger;
226
- const state = node_crypto.randomUUID();
227
- cookieSet(event.cookies, COOKIE_STATE, state);
228
- const params = {
229
- client_id: config.oauth.clientId,
230
- response_type: "code",
231
- redirect_uri: urlConcat(event.url.origin, ROUTE_PATH_REDIRECT_LOGIN),
232
- state,
233
- scope,
234
- audience: config.oauth.audience
235
- };
236
- const paramsStr = core.queryParamsCreate(params);
237
- (_config$logger = config.logger) == null || _config$logger.debug == null || _config$logger.debug("Pre login redirect.", {
238
- params,
239
- state
311
+ handle(_0) {
312
+ return __async(this, arguments, function* ({ event }) {
313
+ var _a2, _b2;
314
+ const state = (0, import_node_crypto.randomUUID)();
315
+ cookieSet(event.cookies, COOKIE_STATE, state);
316
+ const params = {
317
+ client_id: config.oauth.clientId,
318
+ response_type: "code",
319
+ redirect_uri: urlConcat(event.url.origin, ROUTE_PATH_REDIRECT_LOGIN),
320
+ state,
321
+ scope,
322
+ audience: config.oauth.audience
323
+ };
324
+ const paramsStr = (0, import_core4.queryParamsCreate)(params);
325
+ (_b2 = (_a2 = config.logger) == null ? void 0 : _a2.debug) == null ? void 0 : _b2.call(_a2, "Pre login redirect.", { params, state });
326
+ throw (0, import_kit2.redirect)(302, `${authorizeEndpoint}?${paramsStr}`);
240
327
  });
241
- throw kit.redirect(302, `${authorizeEndpoint}?${paramsStr}`);
242
328
  }
243
329
  };
244
330
  };
245
331
 
246
- const ROUTE_PATH_REDIRECT_LOGOUT = "/_armor/redirect/logout";
247
- const routeRedirectLogoutFactory = config => {
248
- // Check if the oauth provider supports a logout path.
332
+ // src/routes/logout.ts
333
+ var import_kit4 = require("@sveltejs/kit");
334
+ var import_core5 = require("@nekm/core");
335
+
336
+ // src/routes/redirect-logout.ts
337
+ var import_kit3 = require("@sveltejs/kit");
338
+ var ROUTE_PATH_REDIRECT_LOGOUT = "/_armor/redirect/logout";
339
+ var routeRedirectLogoutFactory = (config) => {
249
340
  if (!config.oauth.logoutEndpoint) {
250
- return undefined;
341
+ return void 0;
251
342
  }
252
343
  return {
253
344
  path: ROUTE_PATH_REDIRECT_LOGOUT,
254
- async handle({
255
- event
256
- }) {
257
- var _config$logger;
258
- (_config$logger = config.logger) == null || _config$logger.debug == null || _config$logger.debug("Handle logout redirect callback.");
259
- await config.session.logout(event);
260
- throw kit.redirect(302, "/");
345
+ handle(_0) {
346
+ return __async(this, arguments, function* ({ event }) {
347
+ var _a2, _b;
348
+ (_b = (_a2 = config.logger) == null ? void 0 : _a2.debug) == null ? void 0 : _b.call(_a2, "Handle logout redirect callback.");
349
+ yield config.session.logout(event);
350
+ throw (0, import_kit3.redirect)(302, "/");
351
+ });
261
352
  }
262
353
  };
263
354
  };
264
355
 
265
- const ROUTE_PATH_LOGOUT = ARMOR_LOGOUT;
266
- const routeLogoutFactory = config => {
267
- var _config$oauth$logoutR;
268
- // Check if the oauth provider supports a logout path.
356
+ // src/routes/logout.ts
357
+ var ROUTE_PATH_LOGOUT = ARMOR_LOGOUT;
358
+ var routeLogoutFactory = (config) => {
359
+ var _a;
269
360
  if (!config.oauth.logoutEndpoint) {
270
- return undefined;
361
+ return void 0;
271
362
  }
272
- const returnTo = (_config$oauth$logoutR = config.oauth.logoutReturnToParam) != null ? _config$oauth$logoutR : "logout_uri";
363
+ const returnTo = (_a = config.oauth.logoutReturnToParam) != null ? _a : "logout_uri";
273
364
  return {
274
365
  path: ROUTE_PATH_LOGOUT,
275
- async handle({
276
- event
277
- }) {
278
- var _config$logger;
279
- const params = {
280
- [returnTo]: urlConcat(event.url.origin, ROUTE_PATH_REDIRECT_LOGOUT),
281
- client_id: config.oauth.clientId
282
- };
283
- const paramsStr = core.queryParamsCreate(params);
284
- (_config$logger = config.logger) == null || _config$logger.debug == null || _config$logger.debug("Pre logout redirect.", {
285
- params
366
+ handle(_0) {
367
+ return __async(this, arguments, function* ({ event }) {
368
+ var _a2, _b2;
369
+ const params = {
370
+ [returnTo]: urlConcat(event.url.origin, ROUTE_PATH_REDIRECT_LOGOUT),
371
+ client_id: config.oauth.clientId
372
+ };
373
+ const paramsStr = (0, import_core5.queryParamsCreate)(params);
374
+ (_b2 = (_a2 = config.logger) == null ? void 0 : _a2.debug) == null ? void 0 : _b2.call(_a2, "Pre logout redirect.", { params });
375
+ throw (0, import_kit4.redirect)(302, `${config.oauth.logoutEndpoint}?${paramsStr}`);
286
376
  });
287
- throw kit.redirect(302, `${config.oauth.logoutEndpoint}?${paramsStr}`);
288
377
  }
289
378
  };
290
379
  };
291
380
 
292
- const routeFactories = Object.freeze([routeLoginFactory, routeLogoutFactory, routeRedirectLoginFactory, routeRedirectLogoutFactory]);
381
+ // src/routes/routes.ts
382
+ var routeFactories = Object.freeze([
383
+ routeLoginFactory,
384
+ routeLogoutFactory,
385
+ routeRedirectLoginFactory,
386
+ routeRedirectLogoutFactory
387
+ ]);
293
388
  function routeByPathFactory(config) {
294
- // @ts-expect-error Incorrect typing error.
295
- return new Map(routeFactories.map(routeFactory => routeFactory(config)).filter(route => Boolean(route))
296
- // @ts-expect-error Incorrect typing error.
297
- .map(route => [route.path, route]));
389
+ return new Map(
390
+ routeFactories.map((routeFactory) => routeFactory(config)).filter((route) => Boolean(route)).map((route) => [route.path, route])
391
+ );
298
392
  }
299
393
 
394
+ // src/errors.ts
395
+ var ArmorError = class extends Error {
396
+ };
397
+ var ArmorOpenIdConfigError = class extends ArmorError {
398
+ };
399
+ var ArmorAuthMissingError = class extends ArmorError {
400
+ };
401
+ var ArmorRefreshError = class extends ArmorError {
402
+ };
403
+
404
+ // src/utils/refresh.ts
405
+ var import_jose3 = require("jose");
406
+ var import_kit5 = require("@sveltejs/kit");
300
407
  function armorRefreshFactory(config) {
301
- var _config$oauth$refresh, _config$oauth$jwksEnd;
302
- const refreshEndpoint = (_config$oauth$refresh = config.oauth.refreshEndpoint) != null ? _config$oauth$refresh : urlConcat(config.oauth.baseUrl, "oauth2/token");
303
- const jwksUrl = new URL((_config$oauth$jwksEnd = config.oauth.jwksEndpoint) != null ? _config$oauth$jwksEnd : urlConcat(config.oauth.baseUrl, ".well-known/jwks.json"));
304
- const refresh = async (fetch, refreshToken) => {
305
- var _json$refresh_token, _config$logger, _config$logger2;
408
+ var _a, _b;
409
+ const refreshEndpoint = (_a = config.oauth.refreshEndpoint) != null ? _a : urlConcat(config.oauth.baseUrl, "oauth2/token");
410
+ const jwksUrl = new URL(
411
+ (_b = config.oauth.jwksEndpoint) != null ? _b : urlConcat(config.oauth.baseUrl, ".well-known/jwks.json")
412
+ );
413
+ const refresh = (fetch2, refreshToken) => __async(null, null, function* () {
414
+ var _a2, _b2, _c2, _d, _e;
306
415
  const body = new URLSearchParams({
307
416
  grant_type: "refresh_token",
308
417
  client_id: config.oauth.clientId,
@@ -312,7 +421,7 @@ function armorRefreshFactory(config) {
312
421
  if (config.oauth.scope) {
313
422
  body.set("scope", config.oauth.scope);
314
423
  }
315
- const response = await fetch(refreshEndpoint, {
424
+ const response = yield fetch2(refreshEndpoint, {
316
425
  method: "POST",
317
426
  headers: {
318
427
  "Content-Type": "application/x-www-form-urlencoded",
@@ -321,143 +430,139 @@ function armorRefreshFactory(config) {
321
430
  body: body.toString()
322
431
  });
323
432
  if (!response.ok) {
324
- const error = await response.text();
433
+ const error = yield response.text();
325
434
  throw new ArmorRefreshError(`Could not refresh token: ${error}`);
326
435
  }
327
- const json = await response.json();
328
- const newExchange = {
329
- ...json,
330
- refresh_token: (_json$refresh_token = json.refresh_token) != null ? _json$refresh_token : refreshToken
331
- };
332
- (_config$logger = config.logger) == null || _config$logger.debug == null || _config$logger.debug("Exchange code for tokens.", {
333
- newExchange
436
+ const json = yield response.json();
437
+ const newExchange = __spreadProps(__spreadValues({}, json), {
438
+ refresh_token: (_a2 = json.refresh_token) != null ? _a2 : refreshToken
334
439
  });
335
- const jwks = jose.createRemoteJWKSet(jwksUrl);
336
- const [idToken, accessToken] = await Promise.all([jwtVerifyIdToken(config, jwks, newExchange.id_token), jwtVerifyAccessToken(config, jwks, newExchange.access_token)]);
337
- (_config$logger2 = config.logger) == null || _config$logger2.debug == null || _config$logger2.debug("Extract and verify tokens.", {
440
+ (_c2 = (_b2 = config.logger) == null ? void 0 : _b2.debug) == null ? void 0 : _c2.call(_b2, "Exchange code for tokens.", { newExchange });
441
+ const jwks = (0, import_jose3.createRemoteJWKSet)(jwksUrl);
442
+ const [idToken, accessToken] = yield Promise.all([
443
+ jwtVerifyIdToken(config, jwks, newExchange.id_token),
444
+ jwtVerifyAccessToken(config, jwks, newExchange.access_token)
445
+ ]);
446
+ (_e = (_d = config.logger) == null ? void 0 : _d.debug) == null ? void 0 : _e.call(_d, "Extract and verify tokens.", {
338
447
  idToken,
339
448
  accessToken
340
449
  });
341
- const validTokens = exchangeToTokens(newExchange, idToken, accessToken);
450
+ const validTokens = exchangeToTokens(
451
+ newExchange,
452
+ idToken,
453
+ accessToken
454
+ );
342
455
  return validTokens;
343
- };
456
+ });
344
457
  return {
345
458
  refresh,
346
- async ensureValidToken(event, tokens, fn) {
347
- try {
348
- let validTokens = tokens;
349
- if (shouldRefresh(tokens)) {
350
- var _config$logger3;
351
- (_config$logger3 = config.logger) == null || _config$logger3.debug == null || _config$logger3.debug("Tokens has expired. Refreshing...");
352
- if (!tokens.exchange.refresh_token) {
353
- throw kit.redirect(302, ROUTE_PATH_LOGIN);
459
+ ensureValidToken(event, tokens, fn) {
460
+ return __async(this, null, function* () {
461
+ var _a2, _b2;
462
+ try {
463
+ let validTokens = tokens;
464
+ if (shouldRefresh(tokens)) {
465
+ (_b2 = (_a2 = config.logger) == null ? void 0 : _a2.debug) == null ? void 0 : _b2.call(_a2, "Tokens has expired. Refreshing...");
466
+ if (!tokens.exchange.refresh_token) {
467
+ throw (0, import_kit5.redirect)(302, ROUTE_PATH_LOGIN);
468
+ }
469
+ validTokens = yield refresh(fetch, tokens.exchange.refresh_token);
470
+ yield config.session.login(event, validTokens);
354
471
  }
355
- validTokens = await refresh(fetch, tokens.exchange.refresh_token);
356
- await config.session.login(event, validTokens);
357
- }
358
- return fn(validTokens);
359
- } catch (error) {
360
- if (error instanceof ArmorRefreshError) {
361
- throw kit.redirect(302, ROUTE_PATH_LOGIN);
472
+ return fn(validTokens);
473
+ } catch (error) {
474
+ if (error instanceof ArmorRefreshError) {
475
+ throw (0, import_kit5.redirect)(302, ROUTE_PATH_LOGIN);
476
+ }
477
+ throw error;
362
478
  }
363
- throw error;
364
- }
479
+ });
365
480
  }
366
481
  };
367
482
  }
368
483
 
484
+ // src/session/cookie.ts
369
485
  function cookieSessionGetTokens({
370
486
  cookies
371
487
  }) {
372
488
  return cookies.get(COOKIE_TOKENS);
373
489
  }
374
- function cookieSessionLogin({
375
- cookies
376
- }, tokens) {
490
+ function cookieSessionLogin({ cookies }, tokens) {
377
491
  cookieSet(cookies, COOKIE_TOKENS, tokens);
378
492
  }
379
- function cookieSessionLogout({
380
- cookies
381
- }) {
493
+ function cookieSessionLogout({ cookies }) {
382
494
  cookieDelete(cookies, COOKIE_TOKENS);
383
495
  }
384
- function armorCookieSessionGet({
385
- cookies
386
- }) {
496
+ function armorCookieSessionGet({ cookies }) {
387
497
  const tokens = cookieGet(cookies, COOKIE_TOKENS);
388
498
  if (!tokens) {
389
499
  throw new ArmorAuthMissingError();
390
500
  }
391
501
  return tokens;
392
502
  }
393
- const armorCookieSession = {
503
+ var armorCookieSession = {
394
504
  getTokens: cookieSessionGetTokens,
395
505
  login: cookieSessionLogin,
396
506
  logout: cookieSessionLogout
397
507
  };
398
508
 
509
+ // src/index.ts
399
510
  function armor(config) {
400
511
  const routeByPath = routeByPathFactory(config);
401
512
  const refresh = armorRefreshFactory(config);
402
- return {
403
- ...refresh,
404
- async handle({
405
- event,
406
- resolve
407
- }) {
408
- const route = routeByPath.get(event.url.pathname);
409
- if (route) {
410
- return route.handle({
411
- event,
412
- resolve
413
- });
414
- }
415
- const tokens = await config.session.getTokens(event);
416
- if (!tokens) {
417
- var _config$logger;
418
- (_config$logger = config.logger) == null || _config$logger.warning == null || _config$logger.warning("Could not find tokens. Redirecting to login.");
419
- throw kit.redirect(302, ROUTE_PATH_LOGIN);
420
- }
421
- return refresh.ensureValidToken(event, tokens, () => resolve(event));
513
+ return __spreadProps(__spreadValues({}, refresh), {
514
+ handle(_0) {
515
+ return __async(this, arguments, function* ({ event, resolve }) {
516
+ var _a2, _b;
517
+ const route = routeByPath.get(event.url.pathname);
518
+ if (route) {
519
+ return route.handle({ event, resolve });
520
+ }
521
+ const tokens = yield config.session.getTokens(event);
522
+ if (!tokens) {
523
+ (_b = (_a2 = config.logger) == null ? void 0 : _a2.warning) == null ? void 0 : _b.call(
524
+ _a2,
525
+ "Could not find tokens. Redirecting to login."
526
+ );
527
+ throw (0, import_kit6.redirect)(302, ROUTE_PATH_LOGIN);
528
+ }
529
+ return refresh.ensureValidToken(event, tokens, () => resolve(event));
530
+ });
422
531
  }
423
- };
532
+ });
424
533
  }
425
- /**
426
- * Some IdP's expose a /.well-known/openid-configuration that specifies how to configure.
427
- * Use that to create your config.
428
- * @param config
429
- * @param fetch
430
- */
431
- async function armorConfigFromOpenId(config, fetch) {
432
- var _body$end_session_end;
433
- const fetchToUse = fetch != null ? fetch : global.fetch;
434
- const response = await fetchToUse(config.oauth.openIdConfigEndpoint, {
435
- headers: {
436
- Accept: "application/json"
534
+ function armorConfigFromOpenId(config, fetch2) {
535
+ return __async(this, null, function* () {
536
+ var _a;
537
+ const fetchToUse = fetch2 != null ? fetch2 : global.fetch;
538
+ const response = yield fetchToUse(config.oauth.openIdConfigEndpoint, {
539
+ headers: {
540
+ Accept: "application/json"
541
+ }
542
+ });
543
+ if (!response.ok) {
544
+ const text = yield response.text();
545
+ throw new ArmorOpenIdConfigError(text);
437
546
  }
547
+ const body = yield response.json();
548
+ return __spreadProps(__spreadValues({}, config), {
549
+ oauth: __spreadProps(__spreadValues({}, config.oauth), {
550
+ tokenEndpoint: body.token_endpoint,
551
+ authorizeEndpoint: body.authorization_endpoint,
552
+ issuer: body.issuer,
553
+ jwksEndpoint: body.jwks_uri,
554
+ logoutEndpoint: (_a = body.end_session_endpoint) != null ? _a : void 0,
555
+ refreshEndpoint: body.token_endpoint
556
+ })
557
+ });
438
558
  });
439
- if (!response.ok) {
440
- const text = await response.text();
441
- throw new ArmorOpenIdConfigError(text);
442
- }
443
- const body = await response.json();
444
- return {
445
- ...config,
446
- oauth: {
447
- ...config.oauth,
448
- tokenEndpoint: body.token_endpoint,
449
- authorizeEndpoint: body.authorization_endpoint,
450
- issuer: body.issuer,
451
- jwksEndpoint: body.jwks_uri,
452
- logoutEndpoint: (_body$end_session_end = body.end_session_endpoint) != null ? _body$end_session_end : undefined,
453
- refreshEndpoint: body.token_endpoint
454
- }
455
- };
456
559
  }
457
-
458
- exports.armor = armor;
459
- exports.armorConfigFromOpenId = armorConfigFromOpenId;
460
- exports.armorCookieSession = armorCookieSession;
461
- exports.armorCookieSessionGet = armorCookieSessionGet;
462
- exports.armorRefreshFactory = armorRefreshFactory;
463
- //# sourceMappingURL=index.js.map
560
+ // Annotate the CommonJS export names for ESM import in node:
561
+ 0 && (module.exports = {
562
+ armor,
563
+ armorConfigFromOpenId,
564
+ armorCookieSession,
565
+ armorCookieSessionGet,
566
+ armorRefreshFactory
567
+ });
568
+ //# sourceMappingURL=index.js.map