@nekm/sveltekit-armor 0.3.1 → 0.3.2
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/browser/index.d.ts +5 -6
- package/dist/index.esm.js +40 -29
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +40 -29
- package/dist/index.js.map +1 -1
- package/dist/utils/refresh.d.ts +6 -2
- package/dist/utils/utils.d.ts +3 -2
- package/package.json +1 -1
- package/src/browser/index.ts +16 -7
- package/src/index.ts +1 -1
- package/src/routes/redirect-login.ts +5 -9
- package/src/routes/refresh.ts +2 -5
- package/src/utils/refresh.ts +40 -22
- package/src/utils/utils.ts +31 -3
package/dist/browser/index.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
readonly idToken: string;
|
|
3
|
-
readonly accessToken: string;
|
|
4
|
-
readonly expiresAt: Date;
|
|
5
|
-
}
|
|
1
|
+
import { ArmorTokens } from "../contracts";
|
|
6
2
|
export declare const ARMOR_REFRESH = "/_armor/refresh";
|
|
7
3
|
export declare const ARMOR_LOGIN = "/_armor/login";
|
|
8
|
-
|
|
4
|
+
type ArmorBrowserTokens = Pick<ArmorTokens, "idToken" | "accessToken">;
|
|
5
|
+
export declare function armorBrowserRefresh(): Promise<ArmorBrowserTokens>;
|
|
6
|
+
export declare function armorBrowserEnsureValidTokens<T>(tokens: ArmorBrowserTokens, fn: (tokens: ArmorBrowserTokens) => T | Promise<T>): Promise<T>;
|
|
7
|
+
export {};
|
package/dist/index.esm.js
CHANGED
|
@@ -15,13 +15,25 @@ function isTokenExchange(value) {
|
|
|
15
15
|
}
|
|
16
16
|
const MINUTES_MS = 60 * 1000;
|
|
17
17
|
function shouldRefresh(tokens) {
|
|
18
|
-
|
|
18
|
+
const accessExpiry = typeof tokens.accessToken !== "string" && tokens.accessToken.exp ? tokens.accessToken.exp : Infinity;
|
|
19
|
+
const expiry = Math.min(tokens.idToken.exp, accessExpiry);
|
|
20
|
+
return expiry < Date.now() + 5 * MINUTES_MS;
|
|
19
21
|
}
|
|
20
22
|
function createExpiresAt(seconds) {
|
|
21
23
|
const now = new Date();
|
|
22
24
|
now.setSeconds(now.getSeconds() + seconds);
|
|
23
25
|
return now;
|
|
24
26
|
}
|
|
27
|
+
function exchangeToTokens(exchange, idToken, accessToken) {
|
|
28
|
+
return {
|
|
29
|
+
exchange,
|
|
30
|
+
idToken: idToken,
|
|
31
|
+
// Generally, IdP's require an audience to get a JWT
|
|
32
|
+
// access token. Most cases, this doesn't matter.
|
|
33
|
+
accessToken: accessToken != null ? accessToken : exchange.access_token,
|
|
34
|
+
expiresAt: createExpiresAt(exchange.expires_in)
|
|
35
|
+
};
|
|
36
|
+
}
|
|
25
37
|
|
|
26
38
|
function jwtIsCompactJwt(token) {
|
|
27
39
|
// Must be three base64url segments
|
|
@@ -177,14 +189,7 @@ const routeRedirectLoginFactory = config => {
|
|
|
177
189
|
const exchange = await exchangeCodeForToken(event.fetch, event.url.origin, code);
|
|
178
190
|
const jwks = createRemoteJWKSet(jwksUrl);
|
|
179
191
|
const [idToken, accessToken] = await Promise.all([jwtVerifyIdToken(config, jwks, exchange.id_token), jwtVerifyAccessToken(config, jwks, exchange.access_token)]);
|
|
180
|
-
await config.session.login(event,
|
|
181
|
-
exchange,
|
|
182
|
-
idToken: idToken,
|
|
183
|
-
// Generally, IdP's require an audience to get a JWT
|
|
184
|
-
// access token. Most cases, this doesn't matter.
|
|
185
|
-
accessToken: accessToken != null ? accessToken : exchange.access_token,
|
|
186
|
-
expiresAt: createExpiresAt(exchange.expires_in)
|
|
187
|
-
});
|
|
192
|
+
await config.session.login(event, exchangeToTokens(exchange, idToken, accessToken));
|
|
188
193
|
throw redirect(302, "/");
|
|
189
194
|
}
|
|
190
195
|
};
|
|
@@ -296,23 +301,31 @@ function armorCreateRefresh(config) {
|
|
|
296
301
|
refresh_token: (_json$refresh_token = json.refresh_token) != null ? _json$refresh_token : refreshToken
|
|
297
302
|
};
|
|
298
303
|
};
|
|
299
|
-
|
|
300
|
-
var _tokens$exchange;
|
|
301
|
-
const refreshToken = (_tokens$exchange = tokens.exchange) == null ? void 0 : _tokens$exchange.refresh_token;
|
|
302
|
-
if (!refreshToken) {
|
|
303
|
-
throw new ArmorRefreshError("Could not find refresh token");
|
|
304
|
-
}
|
|
305
|
-
const newExchange = await refresh(event.fetch, refreshToken);
|
|
304
|
+
const postRefresh = async exchange => {
|
|
306
305
|
const jwks = createRemoteJWKSet(jwksUrl);
|
|
307
|
-
const [idToken, accessToken] = await Promise.all([jwtVerifyIdToken(config, jwks,
|
|
308
|
-
return
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
306
|
+
const [idToken, accessToken] = await Promise.all([jwtVerifyIdToken(config, jwks, exchange.id_token), jwtVerifyAccessToken(config, jwks, exchange.access_token)]);
|
|
307
|
+
return exchangeToTokens(exchange, idToken, accessToken);
|
|
308
|
+
};
|
|
309
|
+
return {
|
|
310
|
+
refresh,
|
|
311
|
+
async ensureValidToken(fetch, tokens, fn) {
|
|
312
|
+
let validTokens = tokens;
|
|
313
|
+
if (shouldRefresh(tokens)) {
|
|
314
|
+
throwIfUndefined(tokens.exchange.refresh_token);
|
|
315
|
+
const newTokens = await refresh(fetch, tokens.exchange.refresh_token);
|
|
316
|
+
validTokens = await postRefresh(newTokens);
|
|
317
|
+
}
|
|
318
|
+
return fn(validTokens);
|
|
319
|
+
},
|
|
320
|
+
async handler(event, tokens) {
|
|
321
|
+
var _tokens$exchange;
|
|
322
|
+
const refreshToken = (_tokens$exchange = tokens.exchange) == null ? void 0 : _tokens$exchange.refresh_token;
|
|
323
|
+
if (!refreshToken) {
|
|
324
|
+
throw new ArmorRefreshError("Could not find refresh token");
|
|
325
|
+
}
|
|
326
|
+
const exchange = await refresh(event.fetch, refreshToken);
|
|
327
|
+
return postRefresh(exchange);
|
|
328
|
+
}
|
|
316
329
|
};
|
|
317
330
|
}
|
|
318
331
|
|
|
@@ -332,12 +345,10 @@ const routeRefreshFactory = config => {
|
|
|
332
345
|
}
|
|
333
346
|
const {
|
|
334
347
|
idToken,
|
|
335
|
-
expiresAt,
|
|
336
348
|
accessToken
|
|
337
|
-
} = await refresh(event, tokens);
|
|
349
|
+
} = await refresh.handler(event, tokens);
|
|
338
350
|
return json({
|
|
339
351
|
idToken,
|
|
340
|
-
expiresAt,
|
|
341
352
|
accessToken
|
|
342
353
|
});
|
|
343
354
|
} catch (ex) {
|
|
@@ -409,7 +420,7 @@ function armor(config) {
|
|
|
409
420
|
try {
|
|
410
421
|
if (shouldRefresh(tokens)) {
|
|
411
422
|
console.log("Refreshing token...");
|
|
412
|
-
await refresh(event, tokens);
|
|
423
|
+
await refresh.handler(event, tokens);
|
|
413
424
|
}
|
|
414
425
|
} catch (error) {
|
|
415
426
|
if (error instanceof ArmorRefreshError) {
|
package/dist/index.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":["../src/utils/utils.ts","../src/utils/jwt.ts","../src/utils/cookie.ts","../src/errors.ts","../src/utils/event.ts","../src/routes/redirect-login.ts","../src/browser/index.ts","../src/routes/login.ts","../src/routes/redirect-logout.ts","../src/routes/logout.ts","../src/utils/refresh.ts","../src/routes/refresh.ts","../src/routes/routes.ts","../src/session/cookie.ts","../src/index.ts"],"sourcesContent":["import { strTrimEnd, strTrimStart } from \"@nekm/core\";\nimport type { ArmorTokenExchange, ArmorTokens } from \"../contracts\";\n\nexport function urlConcat(origin: string, path: string): string {\n\treturn [strTrimEnd(origin, \"/\"), strTrimStart(path, \"/\")].join(\"/\");\n}\n\nexport function isTokenExchange(value: unknown): value is ArmorTokenExchange {\n\tif (typeof value !== \"object\" || value === null) return false;\n\n\tconst obj = value as Record<string, unknown>;\n\n\treturn (\n\t\ttypeof obj.access_token === \"string\" &&\n\t\tobj.token_type === \"Bearer\" &&\n\t\ttypeof obj.expires_in === \"number\" &&\n\t\t// Optional fields\n\t\t(typeof obj.id_token === \"string\" || obj.id_token === undefined) &&\n\t\t(typeof obj.refresh_token === \"string\" ||\n\t\t\tobj.refresh_token === undefined) &&\n\t\t(typeof obj.scope === \"string\" || obj.scope === undefined)\n\t);\n}\n\nconst MINUTES_MS = 60 * 1000;\n\nexport function shouldRefresh(tokens: ArmorTokens) {\n\treturn tokens.expiresAt.getTime() < Date.now() + 5 * MINUTES_MS;\n}\n\nexport function createExpiresAt(seconds: number): Date {\n\tconst now = new Date();\n\tnow.setSeconds(now.getSeconds() + seconds);\n\treturn now;\n}\n","import { ArmorConfig } from \"../contracts\";\nimport { JWTPayload, jwtVerify, JWTVerifyGetKey, JWTVerifyOptions } from \"jose\";\nimport { throwIfUndefined } from \"@nekm/core\";\n\nfunction jwtIsCompactJwt(token: string): boolean {\n\t// Must be three base64url segments\n\tconst parts = token.trim().split(\".\");\n\treturn parts.length === 3 && parts.every((p) => p.length > 0);\n}\n\nexport function jwtVerifyIdToken(\n\tconfig: ArmorConfig,\n\tjwks: JWTVerifyGetKey,\n\tidToken: string,\n): Promise<JWTPayload> {\n\tconst payload = jwtVerifyToken(\n\t\tjwks,\n\t\t{\n\t\t\tissuer: config.oauth.issuer,\n\t\t\taudience: config.oauth.clientId,\n\t\t},\n\t\tidToken,\n\t);\n\tthrowIfUndefined(payload);\n\t// @ts-expect-error We're already verifying non-null above.\n\treturn payload;\n}\n\nexport function jwtVerifyAccessToken(\n\tconfig: ArmorConfig,\n\tjwks: JWTVerifyGetKey,\n\taccessToken: string,\n): Promise<JWTPayload | undefined> {\n\tconst opts: JWTVerifyOptions = { issuer: config.oauth.issuer };\n\n\tif (config.oauth.audience) {\n\t\topts.audience = config.oauth.audience;\n\t}\n\n\treturn jwtVerifyToken(jwks, opts, accessToken);\n}\n\nfunction isInvalidCompactJwt(error: unknown): boolean {\n\treturn Boolean(\n\t\ttypeof error === \"object\" &&\n\t\terror &&\n\t\t\"message\" in error &&\n\t\ttypeof error.message === \"string\" &&\n\t\t/invalid compact jws/gi.test(error.message),\n\t);\n}\n\nasync function jwtVerifyToken(\n\tjwks: JWTVerifyGetKey,\n\topts: JWTVerifyOptions,\n\ttoken: string,\n): Promise<JWTPayload | undefined> {\n\ttry {\n\t\tif (!jwtIsCompactJwt(token)) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst { payload } = await jwtVerify(token, jwks, opts);\n\t\treturn payload;\n\t} catch (error) {\n\t\tif (isInvalidCompactJwt(error)) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tthrow error;\n\t}\n}\n","import { Cookies } from \"@sveltejs/kit\";\n\nexport const COOKIE_TOKENS = \"tokens\";\nexport const COOKIE_STATE = \"state\";\n\nconst cookieDeleteOptions = Object.freeze({ path: \"/\" });\n\nconst cookieSetOptions = Object.freeze({\n\t...cookieDeleteOptions,\n\thttpOnly: true,\n\tsecure: true,\n\tsameSite: \"lax\",\n\tmaxAge: 1800, // 30 minutes\n});\n\nexport function cookieSet(\n\tcookies: Cookies,\n\tkey: string,\n\tvalue: string | object,\n) {\n\tcookies.set(key, JSON.stringify(value), cookieSetOptions);\n}\n\nexport function cookieGetAndDelete<T>(\n\tcookies: Cookies,\n\tkey: string,\n): T | undefined {\n\tconst value = cookieGet<T>(cookies, key);\n\n\tif (value) {\n\t\tcookies.delete(key, cookieDeleteOptions);\n\t}\n\n\treturn value;\n}\n\nexport function cookieGet<T>(cookies: Cookies, key: string): T | undefined {\n\tconst value = cookies.get(key);\n\n\treturn !value ? undefined : JSON.parse(value);\n}\n\nexport function cookieDelete(cookies: Cookies, key: string): void {\n\tcookies.delete(key, cookieDeleteOptions);\n}\n","export class ArmorError extends Error {}\nexport class ArmorOpenIdConfigError extends ArmorError {}\nexport class ArmorInvalidStateError extends ArmorError {}\nexport class ArmorAuthMissingError extends ArmorError {}\nexport class ArmorRefreshError extends ArmorError {}\n","import { RequestEvent } from \"@sveltejs/kit\";\nimport { COOKIE_STATE, cookieGetAndDelete } from \"./cookie\";\nimport { ArmorInvalidStateError } from \"../errors\";\n\nexport function eventStateValidOrThrow(event: RequestEvent): void {\n\tconst state = event.url.searchParams.get(\"state\") ?? undefined;\n\tconst stateCookie = cookieGetAndDelete(event.cookies, COOKIE_STATE);\n\n\tif (state !== stateCookie) {\n\t\tthrow new ArmorInvalidStateError();\n\t}\n}\n","import { redirect } from \"@sveltejs/kit\";\nimport type {\n\tArmorConfig,\n\tArmorIdToken,\n\tArmorTokenExchange,\n} from \"../contracts\";\nimport { queryParamsCreate, throwIfUndefined } from \"@nekm/core\";\nimport { createRemoteJWKSet } from \"jose\";\nimport type { RouteFactory } from \"./routes\";\nimport { urlConcat, isTokenExchange, createExpiresAt } from \"../utils/utils\";\nimport { jwtVerifyAccessToken, jwtVerifyIdToken } from \"../utils/jwt\";\nimport { eventStateValidOrThrow } from \"../utils/event\";\n\nexport const ROUTE_PATH_REDIRECT_LOGIN = \"/_armor/redirect/login\";\n\nexport const routeRedirectLoginFactory: RouteFactory = (\n\tconfig: ArmorConfig,\n) => {\n\tconst jwksUrl = new URL(\n\t\tconfig.oauth.jwksEndpoint ??\n\t\t\turlConcat(config.oauth.baseUrl, \".well-known/jwks.json\"),\n\t);\n\n\tconst tokenUrl =\n\t\tconfig.oauth.tokenEndpoint ??\n\t\turlConcat(config.oauth.baseUrl, \"oauth2/token\");\n\n\tconst scope = config.oauth.scope ?? \"openid profile email\";\n\n\tasync function exchangeCodeForToken(\n\t\tfetch: typeof global.fetch,\n\t\torigin: string,\n\t\tcode: string,\n\t): Promise<ArmorTokenExchange> {\n\t\tconst params: Record<string, string> = {\n\t\t\tgrant_type: \"authorization_code\",\n\t\t\tclient_id: config.oauth.clientId,\n\t\t\tclient_secret: config.oauth.clientSecret,\n\t\t\tcode,\n\t\t\tredirect_uri: urlConcat(origin, ROUTE_PATH_REDIRECT_LOGIN),\n\t\t\tscope,\n\t\t};\n\n\t\tif (config.oauth.audience) {\n\t\t\tparams.audience = config.oauth.audience;\n\t\t}\n\n\t\tconst response = await fetch(tokenUrl, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\tAccept: \"application/json\",\n\t\t\t},\n\t\t\tbody: new URLSearchParams(params).toString(),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst error = await response.text();\n\t\t\tthrow new Error(`Token exchange failed: ${error}`);\n\t\t}\n\n\t\tconst token = await response.json();\n\n\t\tif (!isTokenExchange(token)) {\n\t\t\tthrow new Error(\"Response is not a valid token exchange.\");\n\t\t}\n\n\t\treturn token;\n\t}\n\n\treturn {\n\t\tpath: ROUTE_PATH_REDIRECT_LOGIN,\n\t\tmethod: \"GET\",\n\t\tasync handle({ event }) {\n\t\t\teventStateValidOrThrow(event);\n\n\t\t\tconst error = event.url.searchParams.get(\"error\") ?? undefined;\n\n\t\t\tif (error) {\n\t\t\t\tconst error_description =\n\t\t\t\t\tevent.url.searchParams.get(\"error_description\") ?? undefined;\n\n\t\t\t\tif (!config.oauth.errorLoginRedirectPath) {\n\t\t\t\t\treturn new Response(`${error}\\n${error_description}`.trimEnd(), {\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t\"Content-Type\": \"text/plain\",\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst errorParams = queryParamsCreate({ error, error_description });\n\t\t\t\tthrow redirect(\n\t\t\t\t\t302,\n\t\t\t\t\t`${config.oauth.errorLoginRedirectPath}?${errorParams}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst code = event.url.searchParams.get(\"code\") ?? undefined;\n\t\t\tthrowIfUndefined(code);\n\n\t\t\tconst exchange = await exchangeCodeForToken(\n\t\t\t\tevent.fetch,\n\t\t\t\tevent.url.origin,\n\t\t\t\tcode,\n\t\t\t);\n\n\t\t\tconst jwks = createRemoteJWKSet(jwksUrl);\n\n\t\t\tconst [idToken, accessToken] = await Promise.all([\n\t\t\t\tjwtVerifyIdToken(config, jwks, exchange.id_token),\n\t\t\t\tjwtVerifyAccessToken(config, jwks, exchange.access_token),\n\t\t\t]);\n\n\t\t\tawait config.session.login(event, {\n\t\t\t\texchange,\n\t\t\t\tidToken: idToken as ArmorIdToken,\n\t\t\t\t// Generally, IdP's require an audience to get a JWT\n\t\t\t\t// access token. Most cases, this doesn't matter.\n\t\t\t\taccessToken: accessToken ?? exchange.access_token,\n\t\t\t\texpiresAt: createExpiresAt(exchange.expires_in),\n\t\t\t});\n\n\t\t\tthrow redirect(302, \"/\");\n\t\t},\n\t};\n};\n","import { ArmorRefreshError } from \"../errors\";\n\nexport interface ArmorBrowserRefresh {\n\treadonly idToken: string;\n\treadonly accessToken: string;\n\treadonly expiresAt: Date;\n}\n\nexport const ARMOR_REFRESH = \"/_armor/refresh\";\nexport const ARMOR_LOGIN = \"/_armor/login\";\n\nexport async function armorBrowserRefresh(): Promise<ArmorBrowserRefresh> {\n\tconst response = await fetch(ARMOR_REFRESH, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t});\n\n\tif (!response.ok) {\n\t\tif (response.status === 401) {\n\t\t\t// eslint-disable-next-line no-undef\n\t\t\twindow.location.href = ARMOR_LOGIN;\n\t\t\tthrow new ArmorRefreshError(\"Redirecting to login\");\n\t\t}\n\n\t\tconst error = await response.text();\n\t\tthrow new ArmorRefreshError(`Could not refresh token: ${error}`);\n\t}\n\n\treturn response.json();\n}\n","import { redirect } from \"@sveltejs/kit\";\nimport type { ArmorConfig } from \"../contracts\";\nimport { queryParamsCreate } from \"@nekm/core\";\nimport { ROUTE_PATH_REDIRECT_LOGIN } from \"./redirect-login\";\nimport { randomUUID } from \"node:crypto\";\nimport type { RouteFactory } from \"./routes\";\nimport { COOKIE_STATE, cookieSet } from \"../utils/cookie\";\nimport { urlConcat } from \"../utils/utils\";\nimport { ARMOR_LOGIN } from \"../browser\";\n\nexport const ROUTE_PATH_LOGIN = ARMOR_LOGIN;\n\nexport const routeLoginFactory: RouteFactory = (config: ArmorConfig) => {\n\tconst authorizeEndpoint =\n\t\tconfig.oauth.authorizeEndpoint ??\n\t\turlConcat(config.oauth.baseUrl, \"oauth2/authorize\");\n\n\tconst scope = config.oauth.scope ?? \"openid profile email\";\n\n\treturn {\n\t\tpath: ROUTE_PATH_LOGIN,\n\t\tmethod: \"GET\",\n\t\tasync handle({ event }) {\n\t\t\tconst state = randomUUID();\n\t\t\tcookieSet(event.cookies, COOKIE_STATE, state);\n\n\t\t\tconst params = queryParamsCreate({\n\t\t\t\tclient_id: config.oauth.clientId,\n\t\t\t\tresponse_type: \"code\",\n\t\t\t\tredirect_uri: urlConcat(event.url.origin, ROUTE_PATH_REDIRECT_LOGIN),\n\t\t\t\tstate,\n\t\t\t\tscope,\n\t\t\t\taudience: config.oauth.audience,\n\t\t\t});\n\n\t\t\tthrow redirect(302, `${authorizeEndpoint}?${params}`);\n\t\t},\n\t};\n};\n","import { redirect } from \"@sveltejs/kit\";\nimport type { ArmorConfig } from \"../contracts\";\nimport type { RouteFactory } from \"./routes\";\nimport { eventStateValidOrThrow } from \"../utils/event\";\n\nexport const ROUTE_PATH_REDIRECT_LOGOUT = \"/_armor/redirect/logout\";\n\nexport const routeRedirectLogoutFactory: RouteFactory = (\n\tconfig: ArmorConfig,\n) => {\n\t// Check if the oauth provider supports a logout path.\n\tif (!config.oauth.logoutEndpoint) {\n\t\treturn undefined;\n\t}\n\n\treturn {\n\t\tpath: ROUTE_PATH_REDIRECT_LOGOUT,\n\t\tmethod: \"GET\",\n\t\tasync handle({ event }) {\n\t\t\teventStateValidOrThrow(event);\n\n\t\t\tawait config.session.logout(event);\n\n\t\t\tthrow redirect(302, \"/\");\n\t\t},\n\t};\n};\n","import { redirect } from \"@sveltejs/kit\";\nimport type { ArmorConfig } from \"../contracts\";\nimport { queryParamsCreate } from \"@nekm/core\";\nimport { ROUTE_PATH_REDIRECT_LOGOUT } from \"./redirect-logout\";\nimport type { RouteFactory } from \"./routes\";\nimport { urlConcat } from \"../utils/utils\";\nimport { randomUUID } from \"node:crypto\";\nimport { COOKIE_STATE, cookieSet } from \"../utils/cookie\";\n\nexport const ROUTE_PATH_LOGOUT = \"/_armor/logout\";\n\nexport const routeLogoutFactory: RouteFactory = (config: ArmorConfig) => {\n\t// Check if the oauth provider supports a logout path.\n\tif (!config.oauth.logoutEndpoint) {\n\t\treturn undefined;\n\t}\n\n\tconst returnTo = config.oauth.logoutReturnToParam ?? \"logout_uri\";\n\n\treturn {\n\t\tpath: ROUTE_PATH_LOGOUT,\n\t\tmethod: \"GET\",\n\t\tasync handle({ event }) {\n\t\t\tconst state = randomUUID();\n\t\t\tcookieSet(event.cookies, COOKIE_STATE, state);\n\n\t\t\tconst params = queryParamsCreate({\n\t\t\t\t[returnTo]: urlConcat(event.url.origin, ROUTE_PATH_REDIRECT_LOGOUT),\n\t\t\t\tclient_id: config.oauth.clientId,\n\t\t\t\tstate,\n\t\t\t});\n\n\t\t\tthrow redirect(302, `${config.oauth.logoutEndpoint}?${params}`);\n\t\t},\n\t};\n};\n","import { createRemoteJWKSet } from \"jose\";\nimport {\n\tArmorConfig,\n\tArmorIdToken,\n\tArmorTokenExchange,\n\tArmorTokens,\n} from \"../contracts\";\nimport { ArmorRefreshError } from \"../errors\";\nimport { createExpiresAt, urlConcat } from \"./utils\";\nimport { jwtVerifyAccessToken, jwtVerifyIdToken } from \"./jwt\";\nimport { RequestEvent } from \"@sveltejs/kit\";\n\nexport function armorCreateRefresh(config: ArmorConfig) {\n\tconst refreshEndpoint =\n\t\tconfig.oauth.refreshEndpoint ??\n\t\turlConcat(config.oauth.baseUrl, \"oauth2/token\");\n\n\tconst jwksUrl = new URL(\n\t\tconfig.oauth.jwksEndpoint ??\n\t\t\turlConcat(config.oauth.baseUrl, \".well-known/jwks.json\"),\n\t);\n\n\tconst refresh = async (\n\t\tfetch: typeof global.fetch,\n\t\trefreshToken: string,\n\t): Promise<ArmorTokenExchange> => {\n\t\tconst body = new URLSearchParams({\n\t\t\tgrant_type: \"refresh_token\",\n\t\t\tclient_id: config.oauth.clientId,\n\t\t\tclient_secret: config.oauth.clientSecret,\n\t\t\trefresh_token: refreshToken,\n\t\t});\n\n\t\tif (config.oauth.scope) {\n\t\t\tbody.set(\"scope\", config.oauth.scope);\n\t\t}\n\n\t\tconst response = await fetch(refreshEndpoint, {\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\tAccept: \"application/json\",\n\t\t\t},\n\t\t\tbody: body.toString(),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst error = await response.text();\n\t\t\tthrow new ArmorRefreshError(`Could not refresh token: ${error}`);\n\t\t}\n\n\t\tconst json: ArmorTokenExchange = await response.json();\n\n\t\treturn {\n\t\t\t...json,\n\t\t\trefresh_token: json.refresh_token ?? refreshToken,\n\t\t};\n\t};\n\n\treturn async (\n\t\tevent: RequestEvent,\n\t\ttokens: ArmorTokens,\n\t): Promise<ArmorTokens> => {\n\t\tconst refreshToken = tokens.exchange?.refresh_token;\n\n\t\tif (!refreshToken) {\n\t\t\tthrow new ArmorRefreshError(\"Could not find refresh token\");\n\t\t}\n\n\t\tconst newExchange = await refresh(event.fetch, refreshToken);\n\n\t\tconst jwks = createRemoteJWKSet(jwksUrl);\n\n\t\tconst [idToken, accessToken] = await Promise.all([\n\t\t\tjwtVerifyIdToken(config, jwks, newExchange.id_token),\n\t\t\tjwtVerifyAccessToken(config, jwks, newExchange.access_token),\n\t\t]);\n\n\t\treturn {\n\t\t\texchange: newExchange,\n\t\t\tidToken: idToken as ArmorIdToken,\n\t\t\t// Generally, IdP's require an audience to get a JWT\n\t\t\t// access token. Most cases, this doesn't matter.\n\t\t\taccessToken: accessToken ?? newExchange.access_token,\n\t\t\texpiresAt: createExpiresAt(newExchange.expires_in),\n\t\t};\n\t};\n}\n","import { error, json } from \"@sveltejs/kit\";\nimport type { ArmorConfig } from \"../contracts\";\nimport type { RouteFactory } from \"./routes\";\nimport { armorCreateRefresh } from \"../utils/refresh\";\nimport { ARMOR_REFRESH } from \"../browser\";\nimport { ArmorRefreshError } from \"../errors\";\n\nexport const ROUTE_PATH_REFRESH = ARMOR_REFRESH;\n\nexport const routeRefreshFactory: RouteFactory = (config: ArmorConfig) => {\n\tconst refresh = armorCreateRefresh(config);\n\n\treturn {\n\t\tpath: ROUTE_PATH_REFRESH,\n\t\tmethod: \"POST\",\n\t\tasync handle({ event }) {\n\t\t\ttry {\n\t\t\t\tconst tokens = await config.session.getTokens(event);\n\n\t\t\t\tif (!tokens) {\n\t\t\t\t\treturn error(401, \"Unauthorized\");\n\t\t\t\t}\n\n\t\t\t\tconst { idToken, expiresAt, accessToken } = await refresh(\n\t\t\t\t\tevent,\n\t\t\t\t\ttokens,\n\t\t\t\t);\n\n\t\t\t\treturn json({ idToken, expiresAt, accessToken });\n\t\t\t} catch (ex) {\n\t\t\t\tif (ex instanceof ArmorRefreshError) {\n\t\t\t\t\treturn error(401, \"Unauthorized\");\n\t\t\t\t}\n\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t},\n\t};\n};\n","import type { Handle } from \"@sveltejs/kit\";\nimport type { ArmorConfig } from \"../contracts\";\nimport { routeLoginFactory } from \"./login\";\nimport { routeLogoutFactory } from \"./logout\";\nimport { routeRedirectLogoutFactory } from \"./redirect-logout\";\nimport { routeRedirectLoginFactory } from \"./redirect-login\";\nimport { routeRefreshFactory } from \"./refresh\";\n\nexport interface Route {\n\treadonly path: string;\n\treadonly handle: Handle;\n\treadonly method: \"GET\" | \"POST\";\n}\n\nexport type RouteFactory = (config: ArmorConfig) => Route | undefined;\n\nconst routeFactories = Object.freeze([\n\trouteLoginFactory,\n\trouteLogoutFactory,\n\trouteRedirectLoginFactory,\n\trouteRedirectLogoutFactory,\n\trouteRefreshFactory,\n]);\n\nexport function routeCreate(config: ArmorConfig): Map<string, Route> {\n\t// @ts-expect-error Incorrect typing error.\n\treturn new Map(\n\t\trouteFactories\n\t\t\t.map((routeFactory) => routeFactory(config))\n\t\t\t.filter((route) => Boolean(route))\n\t\t\t// @ts-expect-error Incorrect typing error.\n\t\t\t.map((route) => [route.path, route]),\n\t);\n}\n","import { RequestEvent } from \"@sveltejs/kit\";\nimport {\n\tCOOKIE_TOKENS,\n\tcookieDelete,\n\tcookieGet,\n\tcookieSet,\n} from \"../utils/cookie\";\nimport { ArmorConfig, ArmorTokens } from \"../contracts\";\nimport { ArmorAuthMissingError } from \"../errors\";\n\nfunction cookieSessionGetTokens({\n\tcookies,\n}: RequestEvent): ArmorTokens | undefined {\n\treturn cookies.get(COOKIE_TOKENS) as ArmorTokens | undefined;\n}\n\nexport function cookieSessionLogin(\n\t{ cookies }: RequestEvent,\n\ttokens: ArmorTokens,\n): void {\n\tcookieSet(cookies, COOKIE_TOKENS, tokens);\n}\n\nfunction cookieSessionLogout({ cookies }: RequestEvent): void {\n\tcookieDelete(cookies, COOKIE_TOKENS);\n}\n\nexport function armorCookieSessionGet({ cookies }: RequestEvent): ArmorTokens {\n\tconst tokens = cookieGet<ArmorTokens>(cookies, COOKIE_TOKENS);\n\n\tif (!tokens) {\n\t\tthrow new ArmorAuthMissingError();\n\t}\n\n\treturn tokens;\n}\n\nexport const armorCookieSession: ArmorConfig[\"session\"] = {\n\tgetTokens: cookieSessionGetTokens,\n\tlogin: cookieSessionLogin,\n\tlogout: cookieSessionLogout,\n};\n","import { redirect, type Handle } from \"@sveltejs/kit\";\nimport { ROUTE_PATH_LOGIN } from \"./routes/login\";\nimport type { ArmorConfig, ArmorOpenIdConfig, ArmorTokens } from \"./contracts\";\nimport { routeCreate } from \"./routes/routes\";\nimport { ArmorOpenIdConfigError, ArmorRefreshError } from \"./errors\";\nimport { shouldRefresh } from \"./utils/utils\";\nimport { armorCreateRefresh } from \"./utils/refresh\";\n\nexport type { ArmorConfig, ArmorTokens };\nexport { armorCookieSession, armorCookieSessionGet } from \"./session/cookie\";\nexport { armorCreateRefresh } from \"./utils/refresh\";\n\nexport function armor(config: ArmorConfig): Handle {\n\tconst routeByPath = routeCreate(config);\n\tconst refresh = armorCreateRefresh(config);\n\n\treturn async ({ event, resolve }) => {\n\t\tconst route = routeByPath.get(event.url.pathname);\n\n\t\tif (route && route.method === event.request.method) {\n\t\t\treturn route.handle({ event, resolve });\n\t\t}\n\n\t\tconst tokens = await config.session.getTokens(event);\n\n\t\tif (!tokens) {\n\t\t\tthrow redirect(302, ROUTE_PATH_LOGIN);\n\t\t}\n\n\t\ttry {\n\t\t\tif (shouldRefresh(tokens)) {\n\t\t\t\tconsole.log(\"Refreshing token...\");\n\t\t\t\tawait refresh(event, tokens);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (error instanceof ArmorRefreshError) {\n\t\t\t\tconsole.error(\"Could not refresh token. Redirect user to login...\");\n\t\t\t\tthrow redirect(302, ROUTE_PATH_LOGIN);\n\t\t\t}\n\n\t\t\tthrow error;\n\t\t}\n\n\t\treturn resolve(event);\n\t};\n}\n\n/**\n * Some IdP's expose a /.well-known/openid-configuration that specifies how to configure.\n * Use that to create your config.\n * @param config\n * @param fetch\n */\nexport async function armorConfigFromOpenId(\n\tconfig: ArmorOpenIdConfig,\n\tfetch?: typeof global.fetch,\n): Promise<ArmorConfig> {\n\tconst fetchToUse = fetch ?? global.fetch;\n\n\tconst response = await fetchToUse(config.oauth.openIdConfigEndpoint, {\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t});\n\n\tif (!response.ok) {\n\t\tconst text = await response.text();\n\t\tthrow new ArmorOpenIdConfigError(text);\n\t}\n\n\tconst body = await response.json();\n\n\treturn {\n\t\t...config,\n\t\toauth: {\n\t\t\t...config.oauth,\n\t\t\ttokenEndpoint: body.token_endpoint,\n\t\t\tauthorizeEndpoint: body.authorization_endpoint,\n\t\t\tissuer: body.issuer,\n\t\t\tjwksEndpoint: body.jwks_uri,\n\t\t\tlogoutEndpoint: body.end_session_endpoint ?? undefined,\n\t\t\trefreshEndpoint: body.token_endpoint,\n\t\t},\n\t};\n}\n"],"names":["urlConcat","origin","path","strTrimEnd","strTrimStart","join","isTokenExchange","value","obj","access_token","token_type","expires_in","id_token","undefined","refresh_token","scope","MINUTES_MS","shouldRefresh","tokens","expiresAt","getTime","Date","now","createExpiresAt","seconds","setSeconds","getSeconds","jwtIsCompactJwt","token","parts","trim","split","length","every","p","jwtVerifyIdToken","config","jwks","idToken","payload","jwtVerifyToken","issuer","oauth","audience","clientId","throwIfUndefined","jwtVerifyAccessToken","accessToken","opts","isInvalidCompactJwt","error","Boolean","message","test","jwtVerify","COOKIE_TOKENS","COOKIE_STATE","cookieDeleteOptions","Object","freeze","cookieSetOptions","httpOnly","secure","sameSite","maxAge","cookieSet","cookies","key","set","JSON","stringify","cookieGetAndDelete","cookieGet","delete","get","parse","cookieDelete","ArmorError","Error","ArmorOpenIdConfigError","ArmorInvalidStateError","ArmorAuthMissingError","ArmorRefreshError","eventStateValidOrThrow","event","_event$url$searchPara","state","url","searchParams","stateCookie","ROUTE_PATH_REDIRECT_LOGIN","routeRedirectLoginFactory","_config$oauth$jwksEnd","_config$oauth$tokenEn","_config$oauth$scope","jwksUrl","URL","jwksEndpoint","baseUrl","tokenUrl","tokenEndpoint","exchangeCodeForToken","fetch","code","params","grant_type","client_id","client_secret","clientSecret","redirect_uri","response","method","headers","Accept","body","URLSearchParams","toString","ok","text","json","handle","_event$url$searchPara3","_event$url$searchPara2","error_description","errorLoginRedirectPath","Response","trimEnd","errorParams","queryParamsCreate","redirect","exchange","createRemoteJWKSet","Promise","all","session","login","ARMOR_REFRESH","ARMOR_LOGIN","ROUTE_PATH_LOGIN","routeLoginFactory","_config$oauth$authori","authorizeEndpoint","randomUUID","response_type","ROUTE_PATH_REDIRECT_LOGOUT","routeRedirectLogoutFactory","logoutEndpoint","logout","ROUTE_PATH_LOGOUT","routeLogoutFactory","_config$oauth$logoutR","returnTo","logoutReturnToParam","armorCreateRefresh","_config$oauth$refresh","refreshEndpoint","refresh","refreshToken","_json$refresh_token","_tokens$exchange","newExchange","ROUTE_PATH_REFRESH","routeRefreshFactory","getTokens","ex","routeFactories","routeCreate","Map","map","routeFactory","filter","route","cookieSessionGetTokens","cookieSessionLogin","cookieSessionLogout","armorCookieSessionGet","armorCookieSession","armor","routeByPath","resolve","pathname","request","console","log","armorConfigFromOpenId","_body$end_session_end","fetchToUse","global","openIdConfigEndpoint","token_endpoint","authorization_endpoint","jwks_uri","end_session_endpoint"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../src/utils/utils.ts","../src/utils/jwt.ts","../src/utils/cookie.ts","../src/errors.ts","../src/utils/event.ts","../src/routes/redirect-login.ts","../src/browser/index.ts","../src/routes/login.ts","../src/routes/redirect-logout.ts","../src/routes/logout.ts","../src/utils/refresh.ts","../src/routes/refresh.ts","../src/routes/routes.ts","../src/session/cookie.ts","../src/index.ts"],"sourcesContent":["import { strTrimEnd, strTrimStart } from \"@nekm/core\";\nimport type {\n\tArmorAccessToken,\n\tArmorIdToken,\n\tArmorTokenExchange,\n\tArmorTokens,\n} from \"../contracts\";\n\nexport function urlConcat(origin: string, path: string): string {\n\treturn [strTrimEnd(origin, \"/\"), strTrimStart(path, \"/\")].join(\"/\");\n}\n\nexport function isTokenExchange(value: unknown): value is ArmorTokenExchange {\n\tif (typeof value !== \"object\" || value === null) return false;\n\n\tconst obj = value as Record<string, unknown>;\n\n\treturn (\n\t\ttypeof obj.access_token === \"string\" &&\n\t\tobj.token_type === \"Bearer\" &&\n\t\ttypeof obj.expires_in === \"number\" &&\n\t\t// Optional fields\n\t\t(typeof obj.id_token === \"string\" || obj.id_token === undefined) &&\n\t\t(typeof obj.refresh_token === \"string\" ||\n\t\t\tobj.refresh_token === undefined) &&\n\t\t(typeof obj.scope === \"string\" || obj.scope === undefined)\n\t);\n}\n\nconst MINUTES_MS = 60 * 1000;\n\nexport function shouldRefresh(\n\ttokens: Pick<ArmorTokens, \"idToken\" | \"accessToken\">,\n): boolean {\n\tconst accessExpiry =\n\t\ttypeof tokens.accessToken !== \"string\" && tokens.accessToken.exp\n\t\t\t? tokens.accessToken.exp\n\t\t\t: Infinity;\n\tconst expiry = Math.min(tokens.idToken.exp, accessExpiry);\n\n\treturn expiry < Date.now() + 5 * MINUTES_MS;\n}\n\nexport function createExpiresAt(seconds: number): Date {\n\tconst now = new Date();\n\tnow.setSeconds(now.getSeconds() + seconds);\n\treturn now;\n}\n\nexport function exchangeToTokens(\n\texchange: ArmorTokenExchange,\n\tidToken: ArmorIdToken,\n\taccessToken?: ArmorAccessToken,\n): ArmorTokens {\n\treturn {\n\t\texchange,\n\t\tidToken: idToken as ArmorIdToken,\n\t\t// Generally, IdP's require an audience to get a JWT\n\t\t// access token. Most cases, this doesn't matter.\n\t\taccessToken: accessToken ?? exchange.access_token,\n\t\texpiresAt: createExpiresAt(exchange.expires_in),\n\t};\n}\n","import { ArmorConfig } from \"../contracts\";\nimport { JWTPayload, jwtVerify, JWTVerifyGetKey, JWTVerifyOptions } from \"jose\";\nimport { throwIfUndefined } from \"@nekm/core\";\n\nfunction jwtIsCompactJwt(token: string): boolean {\n\t// Must be three base64url segments\n\tconst parts = token.trim().split(\".\");\n\treturn parts.length === 3 && parts.every((p) => p.length > 0);\n}\n\nexport function jwtVerifyIdToken(\n\tconfig: ArmorConfig,\n\tjwks: JWTVerifyGetKey,\n\tidToken: string,\n): Promise<JWTPayload> {\n\tconst payload = jwtVerifyToken(\n\t\tjwks,\n\t\t{\n\t\t\tissuer: config.oauth.issuer,\n\t\t\taudience: config.oauth.clientId,\n\t\t},\n\t\tidToken,\n\t);\n\tthrowIfUndefined(payload);\n\t// @ts-expect-error We're already verifying non-null above.\n\treturn payload;\n}\n\nexport function jwtVerifyAccessToken(\n\tconfig: ArmorConfig,\n\tjwks: JWTVerifyGetKey,\n\taccessToken: string,\n): Promise<JWTPayload | undefined> {\n\tconst opts: JWTVerifyOptions = { issuer: config.oauth.issuer };\n\n\tif (config.oauth.audience) {\n\t\topts.audience = config.oauth.audience;\n\t}\n\n\treturn jwtVerifyToken(jwks, opts, accessToken);\n}\n\nfunction isInvalidCompactJwt(error: unknown): boolean {\n\treturn Boolean(\n\t\ttypeof error === \"object\" &&\n\t\terror &&\n\t\t\"message\" in error &&\n\t\ttypeof error.message === \"string\" &&\n\t\t/invalid compact jws/gi.test(error.message),\n\t);\n}\n\nasync function jwtVerifyToken(\n\tjwks: JWTVerifyGetKey,\n\topts: JWTVerifyOptions,\n\ttoken: string,\n): Promise<JWTPayload | undefined> {\n\ttry {\n\t\tif (!jwtIsCompactJwt(token)) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst { payload } = await jwtVerify(token, jwks, opts);\n\t\treturn payload;\n\t} catch (error) {\n\t\tif (isInvalidCompactJwt(error)) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tthrow error;\n\t}\n}\n","import { Cookies } from \"@sveltejs/kit\";\n\nexport const COOKIE_TOKENS = \"tokens\";\nexport const COOKIE_STATE = \"state\";\n\nconst cookieDeleteOptions = Object.freeze({ path: \"/\" });\n\nconst cookieSetOptions = Object.freeze({\n\t...cookieDeleteOptions,\n\thttpOnly: true,\n\tsecure: true,\n\tsameSite: \"lax\",\n\tmaxAge: 1800, // 30 minutes\n});\n\nexport function cookieSet(\n\tcookies: Cookies,\n\tkey: string,\n\tvalue: string | object,\n) {\n\tcookies.set(key, JSON.stringify(value), cookieSetOptions);\n}\n\nexport function cookieGetAndDelete<T>(\n\tcookies: Cookies,\n\tkey: string,\n): T | undefined {\n\tconst value = cookieGet<T>(cookies, key);\n\n\tif (value) {\n\t\tcookies.delete(key, cookieDeleteOptions);\n\t}\n\n\treturn value;\n}\n\nexport function cookieGet<T>(cookies: Cookies, key: string): T | undefined {\n\tconst value = cookies.get(key);\n\n\treturn !value ? undefined : JSON.parse(value);\n}\n\nexport function cookieDelete(cookies: Cookies, key: string): void {\n\tcookies.delete(key, cookieDeleteOptions);\n}\n","export class ArmorError extends Error {}\nexport class ArmorOpenIdConfigError extends ArmorError {}\nexport class ArmorInvalidStateError extends ArmorError {}\nexport class ArmorAuthMissingError extends ArmorError {}\nexport class ArmorRefreshError extends ArmorError {}\n","import { RequestEvent } from \"@sveltejs/kit\";\nimport { COOKIE_STATE, cookieGetAndDelete } from \"./cookie\";\nimport { ArmorInvalidStateError } from \"../errors\";\n\nexport function eventStateValidOrThrow(event: RequestEvent): void {\n\tconst state = event.url.searchParams.get(\"state\") ?? undefined;\n\tconst stateCookie = cookieGetAndDelete(event.cookies, COOKIE_STATE);\n\n\tif (state !== stateCookie) {\n\t\tthrow new ArmorInvalidStateError();\n\t}\n}\n","import { redirect } from \"@sveltejs/kit\";\nimport type {\n\tArmorConfig,\n\tArmorIdToken,\n\tArmorTokenExchange,\n} from \"../contracts\";\nimport { queryParamsCreate, throwIfUndefined } from \"@nekm/core\";\nimport { createRemoteJWKSet } from \"jose\";\nimport type { RouteFactory } from \"./routes\";\nimport { urlConcat, isTokenExchange, exchangeToTokens } from \"../utils/utils\";\nimport { jwtVerifyAccessToken, jwtVerifyIdToken } from \"../utils/jwt\";\nimport { eventStateValidOrThrow } from \"../utils/event\";\n\nexport const ROUTE_PATH_REDIRECT_LOGIN = \"/_armor/redirect/login\";\n\nexport const routeRedirectLoginFactory: RouteFactory = (\n\tconfig: ArmorConfig,\n) => {\n\tconst jwksUrl = new URL(\n\t\tconfig.oauth.jwksEndpoint ??\n\t\t\turlConcat(config.oauth.baseUrl, \".well-known/jwks.json\"),\n\t);\n\n\tconst tokenUrl =\n\t\tconfig.oauth.tokenEndpoint ??\n\t\turlConcat(config.oauth.baseUrl, \"oauth2/token\");\n\n\tconst scope = config.oauth.scope ?? \"openid profile email\";\n\n\tasync function exchangeCodeForToken(\n\t\tfetch: typeof global.fetch,\n\t\torigin: string,\n\t\tcode: string,\n\t): Promise<ArmorTokenExchange> {\n\t\tconst params: Record<string, string> = {\n\t\t\tgrant_type: \"authorization_code\",\n\t\t\tclient_id: config.oauth.clientId,\n\t\t\tclient_secret: config.oauth.clientSecret,\n\t\t\tcode,\n\t\t\tredirect_uri: urlConcat(origin, ROUTE_PATH_REDIRECT_LOGIN),\n\t\t\tscope,\n\t\t};\n\n\t\tif (config.oauth.audience) {\n\t\t\tparams.audience = config.oauth.audience;\n\t\t}\n\n\t\tconst response = await fetch(tokenUrl, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\tAccept: \"application/json\",\n\t\t\t},\n\t\t\tbody: new URLSearchParams(params).toString(),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst error = await response.text();\n\t\t\tthrow new Error(`Token exchange failed: ${error}`);\n\t\t}\n\n\t\tconst token = await response.json();\n\n\t\tif (!isTokenExchange(token)) {\n\t\t\tthrow new Error(\"Response is not a valid token exchange.\");\n\t\t}\n\n\t\treturn token;\n\t}\n\n\treturn {\n\t\tpath: ROUTE_PATH_REDIRECT_LOGIN,\n\t\tmethod: \"GET\",\n\t\tasync handle({ event }) {\n\t\t\teventStateValidOrThrow(event);\n\n\t\t\tconst error = event.url.searchParams.get(\"error\") ?? undefined;\n\n\t\t\tif (error) {\n\t\t\t\tconst error_description =\n\t\t\t\t\tevent.url.searchParams.get(\"error_description\") ?? undefined;\n\n\t\t\t\tif (!config.oauth.errorLoginRedirectPath) {\n\t\t\t\t\treturn new Response(`${error}\\n${error_description}`.trimEnd(), {\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t\"Content-Type\": \"text/plain\",\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst errorParams = queryParamsCreate({ error, error_description });\n\t\t\t\tthrow redirect(\n\t\t\t\t\t302,\n\t\t\t\t\t`${config.oauth.errorLoginRedirectPath}?${errorParams}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst code = event.url.searchParams.get(\"code\") ?? undefined;\n\t\t\tthrowIfUndefined(code);\n\n\t\t\tconst exchange = await exchangeCodeForToken(\n\t\t\t\tevent.fetch,\n\t\t\t\tevent.url.origin,\n\t\t\t\tcode,\n\t\t\t);\n\n\t\t\tconst jwks = createRemoteJWKSet(jwksUrl);\n\n\t\t\tconst [idToken, accessToken] = await Promise.all([\n\t\t\t\tjwtVerifyIdToken(config, jwks, exchange.id_token),\n\t\t\t\tjwtVerifyAccessToken(config, jwks, exchange.access_token),\n\t\t\t]);\n\n\t\t\tawait config.session.login(\n\t\t\t\tevent,\n\t\t\t\texchangeToTokens(exchange, idToken as ArmorIdToken, accessToken),\n\t\t\t);\n\n\t\t\tthrow redirect(302, \"/\");\n\t\t},\n\t};\n};\n","import { ArmorTokens } from \"../contracts\";\nimport { ArmorRefreshError } from \"../errors\";\nimport { shouldRefresh } from \"../utils/utils\";\n\nexport const ARMOR_REFRESH = \"/_armor/refresh\";\nexport const ARMOR_LOGIN = \"/_armor/login\";\n\ntype ArmorBrowserTokens = Pick<ArmorTokens, \"idToken\" | \"accessToken\">;\n\nexport async function armorBrowserRefresh(): Promise<ArmorBrowserTokens> {\n\tconst response = await fetch(ARMOR_REFRESH, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t});\n\n\tif (!response.ok) {\n\t\tif (response.status === 401) {\n\t\t\t// eslint-disable-next-line no-undef\n\t\t\twindow.location.href = ARMOR_LOGIN;\n\t\t\tthrow new ArmorRefreshError(\"Redirecting to login\");\n\t\t}\n\n\t\tconst error = await response.text();\n\t\tthrow new ArmorRefreshError(`Could not refresh token: ${error}`);\n\t}\n\n\treturn response.json();\n}\n\nexport async function armorBrowserEnsureValidTokens<T>(\n\ttokens: ArmorBrowserTokens,\n\tfn: (tokens: ArmorBrowserTokens) => T | Promise<T>,\n): Promise<T> {\n\tconst validTokens = shouldRefresh(tokens)\n\t\t? await armorBrowserRefresh()\n\t\t: tokens;\n\n\treturn fn(validTokens);\n}\n","import { redirect } from \"@sveltejs/kit\";\nimport type { ArmorConfig } from \"../contracts\";\nimport { queryParamsCreate } from \"@nekm/core\";\nimport { ROUTE_PATH_REDIRECT_LOGIN } from \"./redirect-login\";\nimport { randomUUID } from \"node:crypto\";\nimport type { RouteFactory } from \"./routes\";\nimport { COOKIE_STATE, cookieSet } from \"../utils/cookie\";\nimport { urlConcat } from \"../utils/utils\";\nimport { ARMOR_LOGIN } from \"../browser\";\n\nexport const ROUTE_PATH_LOGIN = ARMOR_LOGIN;\n\nexport const routeLoginFactory: RouteFactory = (config: ArmorConfig) => {\n\tconst authorizeEndpoint =\n\t\tconfig.oauth.authorizeEndpoint ??\n\t\turlConcat(config.oauth.baseUrl, \"oauth2/authorize\");\n\n\tconst scope = config.oauth.scope ?? \"openid profile email\";\n\n\treturn {\n\t\tpath: ROUTE_PATH_LOGIN,\n\t\tmethod: \"GET\",\n\t\tasync handle({ event }) {\n\t\t\tconst state = randomUUID();\n\t\t\tcookieSet(event.cookies, COOKIE_STATE, state);\n\n\t\t\tconst params = queryParamsCreate({\n\t\t\t\tclient_id: config.oauth.clientId,\n\t\t\t\tresponse_type: \"code\",\n\t\t\t\tredirect_uri: urlConcat(event.url.origin, ROUTE_PATH_REDIRECT_LOGIN),\n\t\t\t\tstate,\n\t\t\t\tscope,\n\t\t\t\taudience: config.oauth.audience,\n\t\t\t});\n\n\t\t\tthrow redirect(302, `${authorizeEndpoint}?${params}`);\n\t\t},\n\t};\n};\n","import { redirect } from \"@sveltejs/kit\";\nimport type { ArmorConfig } from \"../contracts\";\nimport type { RouteFactory } from \"./routes\";\nimport { eventStateValidOrThrow } from \"../utils/event\";\n\nexport const ROUTE_PATH_REDIRECT_LOGOUT = \"/_armor/redirect/logout\";\n\nexport const routeRedirectLogoutFactory: RouteFactory = (\n\tconfig: ArmorConfig,\n) => {\n\t// Check if the oauth provider supports a logout path.\n\tif (!config.oauth.logoutEndpoint) {\n\t\treturn undefined;\n\t}\n\n\treturn {\n\t\tpath: ROUTE_PATH_REDIRECT_LOGOUT,\n\t\tmethod: \"GET\",\n\t\tasync handle({ event }) {\n\t\t\teventStateValidOrThrow(event);\n\n\t\t\tawait config.session.logout(event);\n\n\t\t\tthrow redirect(302, \"/\");\n\t\t},\n\t};\n};\n","import { redirect } from \"@sveltejs/kit\";\nimport type { ArmorConfig } from \"../contracts\";\nimport { queryParamsCreate } from \"@nekm/core\";\nimport { ROUTE_PATH_REDIRECT_LOGOUT } from \"./redirect-logout\";\nimport type { RouteFactory } from \"./routes\";\nimport { urlConcat } from \"../utils/utils\";\nimport { randomUUID } from \"node:crypto\";\nimport { COOKIE_STATE, cookieSet } from \"../utils/cookie\";\n\nexport const ROUTE_PATH_LOGOUT = \"/_armor/logout\";\n\nexport const routeLogoutFactory: RouteFactory = (config: ArmorConfig) => {\n\t// Check if the oauth provider supports a logout path.\n\tif (!config.oauth.logoutEndpoint) {\n\t\treturn undefined;\n\t}\n\n\tconst returnTo = config.oauth.logoutReturnToParam ?? \"logout_uri\";\n\n\treturn {\n\t\tpath: ROUTE_PATH_LOGOUT,\n\t\tmethod: \"GET\",\n\t\tasync handle({ event }) {\n\t\t\tconst state = randomUUID();\n\t\t\tcookieSet(event.cookies, COOKIE_STATE, state);\n\n\t\t\tconst params = queryParamsCreate({\n\t\t\t\t[returnTo]: urlConcat(event.url.origin, ROUTE_PATH_REDIRECT_LOGOUT),\n\t\t\t\tclient_id: config.oauth.clientId,\n\t\t\t\tstate,\n\t\t\t});\n\n\t\t\tthrow redirect(302, `${config.oauth.logoutEndpoint}?${params}`);\n\t\t},\n\t};\n};\n","import { createRemoteJWKSet } from \"jose\";\nimport {\n\tArmorConfig,\n\tArmorIdToken,\n\tArmorTokenExchange,\n\tArmorTokens,\n} from \"../contracts\";\nimport { ArmorRefreshError } from \"../errors\";\nimport { exchangeToTokens, shouldRefresh, urlConcat } from \"./utils\";\nimport { jwtVerifyAccessToken, jwtVerifyIdToken } from \"./jwt\";\nimport { RequestEvent } from \"@sveltejs/kit\";\nimport { throwIfUndefined } from \"@nekm/core\";\n\nexport function armorCreateRefresh(config: ArmorConfig) {\n\tconst refreshEndpoint =\n\t\tconfig.oauth.refreshEndpoint ??\n\t\turlConcat(config.oauth.baseUrl, \"oauth2/token\");\n\n\tconst jwksUrl = new URL(\n\t\tconfig.oauth.jwksEndpoint ??\n\t\t\turlConcat(config.oauth.baseUrl, \".well-known/jwks.json\"),\n\t);\n\n\tconst refresh = async (\n\t\tfetch: typeof global.fetch,\n\t\trefreshToken: string,\n\t): Promise<ArmorTokenExchange> => {\n\t\tconst body = new URLSearchParams({\n\t\t\tgrant_type: \"refresh_token\",\n\t\t\tclient_id: config.oauth.clientId,\n\t\t\tclient_secret: config.oauth.clientSecret,\n\t\t\trefresh_token: refreshToken,\n\t\t});\n\n\t\tif (config.oauth.scope) {\n\t\t\tbody.set(\"scope\", config.oauth.scope);\n\t\t}\n\n\t\tconst response = await fetch(refreshEndpoint, {\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\tAccept: \"application/json\",\n\t\t\t},\n\t\t\tbody: body.toString(),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst error = await response.text();\n\t\t\tthrow new ArmorRefreshError(`Could not refresh token: ${error}`);\n\t\t}\n\n\t\tconst json: ArmorTokenExchange = await response.json();\n\n\t\treturn {\n\t\t\t...json,\n\t\t\trefresh_token: json.refresh_token ?? refreshToken,\n\t\t};\n\t};\n\n\tconst postRefresh = async (\n\t\texchange: ArmorTokenExchange,\n\t): Promise<ArmorTokens> => {\n\t\tconst jwks = createRemoteJWKSet(jwksUrl);\n\n\t\tconst [idToken, accessToken] = await Promise.all([\n\t\t\tjwtVerifyIdToken(config, jwks, exchange.id_token),\n\t\t\tjwtVerifyAccessToken(config, jwks, exchange.access_token),\n\t\t]);\n\n\t\treturn exchangeToTokens(exchange, idToken as ArmorIdToken, accessToken);\n\t};\n\n\treturn {\n\t\trefresh,\n\t\tasync ensureValidToken<T>(\n\t\t\tfetch: typeof global.fetch,\n\t\t\ttokens: ArmorTokens,\n\t\t\tfn: (tokens: ArmorTokens) => T | Promise<T>,\n\t\t): Promise<T> {\n\t\t\tlet validTokens = tokens;\n\n\t\t\tif (shouldRefresh(tokens)) {\n\t\t\t\tthrowIfUndefined(tokens.exchange.refresh_token);\n\t\t\t\tconst newTokens = await refresh(fetch, tokens.exchange.refresh_token);\n\t\t\t\tvalidTokens = await postRefresh(newTokens);\n\t\t\t}\n\n\t\t\treturn fn(validTokens);\n\t\t},\n\t\tasync handler(\n\t\t\tevent: RequestEvent,\n\t\t\ttokens: ArmorTokens,\n\t\t): Promise<ArmorTokens> {\n\t\t\tconst refreshToken = tokens.exchange?.refresh_token;\n\n\t\t\tif (!refreshToken) {\n\t\t\t\tthrow new ArmorRefreshError(\"Could not find refresh token\");\n\t\t\t}\n\n\t\t\tconst exchange = await refresh(event.fetch, refreshToken);\n\n\t\t\treturn postRefresh(exchange);\n\t\t},\n\t};\n}\n","import { error, json } from \"@sveltejs/kit\";\nimport type { ArmorConfig } from \"../contracts\";\nimport type { RouteFactory } from \"./routes\";\nimport { armorCreateRefresh } from \"../utils/refresh\";\nimport { ARMOR_REFRESH } from \"../browser\";\nimport { ArmorRefreshError } from \"../errors\";\n\nexport const ROUTE_PATH_REFRESH = ARMOR_REFRESH;\n\nexport const routeRefreshFactory: RouteFactory = (config: ArmorConfig) => {\n\tconst refresh = armorCreateRefresh(config);\n\n\treturn {\n\t\tpath: ROUTE_PATH_REFRESH,\n\t\tmethod: \"POST\",\n\t\tasync handle({ event }) {\n\t\t\ttry {\n\t\t\t\tconst tokens = await config.session.getTokens(event);\n\n\t\t\t\tif (!tokens) {\n\t\t\t\t\treturn error(401, \"Unauthorized\");\n\t\t\t\t}\n\n\t\t\t\tconst { idToken, accessToken } = await refresh.handler(event, tokens);\n\n\t\t\t\treturn json({ idToken, accessToken });\n\t\t\t} catch (ex) {\n\t\t\t\tif (ex instanceof ArmorRefreshError) {\n\t\t\t\t\treturn error(401, \"Unauthorized\");\n\t\t\t\t}\n\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t},\n\t};\n};\n","import type { Handle } from \"@sveltejs/kit\";\nimport type { ArmorConfig } from \"../contracts\";\nimport { routeLoginFactory } from \"./login\";\nimport { routeLogoutFactory } from \"./logout\";\nimport { routeRedirectLogoutFactory } from \"./redirect-logout\";\nimport { routeRedirectLoginFactory } from \"./redirect-login\";\nimport { routeRefreshFactory } from \"./refresh\";\n\nexport interface Route {\n\treadonly path: string;\n\treadonly handle: Handle;\n\treadonly method: \"GET\" | \"POST\";\n}\n\nexport type RouteFactory = (config: ArmorConfig) => Route | undefined;\n\nconst routeFactories = Object.freeze([\n\trouteLoginFactory,\n\trouteLogoutFactory,\n\trouteRedirectLoginFactory,\n\trouteRedirectLogoutFactory,\n\trouteRefreshFactory,\n]);\n\nexport function routeCreate(config: ArmorConfig): Map<string, Route> {\n\t// @ts-expect-error Incorrect typing error.\n\treturn new Map(\n\t\trouteFactories\n\t\t\t.map((routeFactory) => routeFactory(config))\n\t\t\t.filter((route) => Boolean(route))\n\t\t\t// @ts-expect-error Incorrect typing error.\n\t\t\t.map((route) => [route.path, route]),\n\t);\n}\n","import { RequestEvent } from \"@sveltejs/kit\";\nimport {\n\tCOOKIE_TOKENS,\n\tcookieDelete,\n\tcookieGet,\n\tcookieSet,\n} from \"../utils/cookie\";\nimport { ArmorConfig, ArmorTokens } from \"../contracts\";\nimport { ArmorAuthMissingError } from \"../errors\";\n\nfunction cookieSessionGetTokens({\n\tcookies,\n}: RequestEvent): ArmorTokens | undefined {\n\treturn cookies.get(COOKIE_TOKENS) as ArmorTokens | undefined;\n}\n\nexport function cookieSessionLogin(\n\t{ cookies }: RequestEvent,\n\ttokens: ArmorTokens,\n): void {\n\tcookieSet(cookies, COOKIE_TOKENS, tokens);\n}\n\nfunction cookieSessionLogout({ cookies }: RequestEvent): void {\n\tcookieDelete(cookies, COOKIE_TOKENS);\n}\n\nexport function armorCookieSessionGet({ cookies }: RequestEvent): ArmorTokens {\n\tconst tokens = cookieGet<ArmorTokens>(cookies, COOKIE_TOKENS);\n\n\tif (!tokens) {\n\t\tthrow new ArmorAuthMissingError();\n\t}\n\n\treturn tokens;\n}\n\nexport const armorCookieSession: ArmorConfig[\"session\"] = {\n\tgetTokens: cookieSessionGetTokens,\n\tlogin: cookieSessionLogin,\n\tlogout: cookieSessionLogout,\n};\n","import { redirect, type Handle } from \"@sveltejs/kit\";\nimport { ROUTE_PATH_LOGIN } from \"./routes/login\";\nimport type { ArmorConfig, ArmorOpenIdConfig, ArmorTokens } from \"./contracts\";\nimport { routeCreate } from \"./routes/routes\";\nimport { ArmorOpenIdConfigError, ArmorRefreshError } from \"./errors\";\nimport { shouldRefresh } from \"./utils/utils\";\nimport { armorCreateRefresh } from \"./utils/refresh\";\n\nexport type { ArmorConfig, ArmorTokens };\nexport { armorCookieSession, armorCookieSessionGet } from \"./session/cookie\";\nexport { armorCreateRefresh } from \"./utils/refresh\";\n\nexport function armor(config: ArmorConfig): Handle {\n\tconst routeByPath = routeCreate(config);\n\tconst refresh = armorCreateRefresh(config);\n\n\treturn async ({ event, resolve }) => {\n\t\tconst route = routeByPath.get(event.url.pathname);\n\n\t\tif (route && route.method === event.request.method) {\n\t\t\treturn route.handle({ event, resolve });\n\t\t}\n\n\t\tconst tokens = await config.session.getTokens(event);\n\n\t\tif (!tokens) {\n\t\t\tthrow redirect(302, ROUTE_PATH_LOGIN);\n\t\t}\n\n\t\ttry {\n\t\t\tif (shouldRefresh(tokens)) {\n\t\t\t\tconsole.log(\"Refreshing token...\");\n\t\t\t\tawait refresh.handler(event, tokens);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (error instanceof ArmorRefreshError) {\n\t\t\t\tconsole.error(\"Could not refresh token. Redirect user to login...\");\n\t\t\t\tthrow redirect(302, ROUTE_PATH_LOGIN);\n\t\t\t}\n\n\t\t\tthrow error;\n\t\t}\n\n\t\treturn resolve(event);\n\t};\n}\n\n/**\n * Some IdP's expose a /.well-known/openid-configuration that specifies how to configure.\n * Use that to create your config.\n * @param config\n * @param fetch\n */\nexport async function armorConfigFromOpenId(\n\tconfig: ArmorOpenIdConfig,\n\tfetch?: typeof global.fetch,\n): Promise<ArmorConfig> {\n\tconst fetchToUse = fetch ?? global.fetch;\n\n\tconst response = await fetchToUse(config.oauth.openIdConfigEndpoint, {\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t});\n\n\tif (!response.ok) {\n\t\tconst text = await response.text();\n\t\tthrow new ArmorOpenIdConfigError(text);\n\t}\n\n\tconst body = await response.json();\n\n\treturn {\n\t\t...config,\n\t\toauth: {\n\t\t\t...config.oauth,\n\t\t\ttokenEndpoint: body.token_endpoint,\n\t\t\tauthorizeEndpoint: body.authorization_endpoint,\n\t\t\tissuer: body.issuer,\n\t\t\tjwksEndpoint: body.jwks_uri,\n\t\t\tlogoutEndpoint: body.end_session_endpoint ?? undefined,\n\t\t\trefreshEndpoint: body.token_endpoint,\n\t\t},\n\t};\n}\n"],"names":["urlConcat","origin","path","strTrimEnd","strTrimStart","join","isTokenExchange","value","obj","access_token","token_type","expires_in","id_token","undefined","refresh_token","scope","MINUTES_MS","shouldRefresh","tokens","accessExpiry","accessToken","exp","Infinity","expiry","Math","min","idToken","Date","now","createExpiresAt","seconds","setSeconds","getSeconds","exchangeToTokens","exchange","expiresAt","jwtIsCompactJwt","token","parts","trim","split","length","every","p","jwtVerifyIdToken","config","jwks","payload","jwtVerifyToken","issuer","oauth","audience","clientId","throwIfUndefined","jwtVerifyAccessToken","opts","isInvalidCompactJwt","error","Boolean","message","test","jwtVerify","COOKIE_TOKENS","COOKIE_STATE","cookieDeleteOptions","Object","freeze","cookieSetOptions","httpOnly","secure","sameSite","maxAge","cookieSet","cookies","key","set","JSON","stringify","cookieGetAndDelete","cookieGet","delete","get","parse","cookieDelete","ArmorError","Error","ArmorOpenIdConfigError","ArmorInvalidStateError","ArmorAuthMissingError","ArmorRefreshError","eventStateValidOrThrow","event","_event$url$searchPara","state","url","searchParams","stateCookie","ROUTE_PATH_REDIRECT_LOGIN","routeRedirectLoginFactory","_config$oauth$jwksEnd","_config$oauth$tokenEn","_config$oauth$scope","jwksUrl","URL","jwksEndpoint","baseUrl","tokenUrl","tokenEndpoint","exchangeCodeForToken","fetch","code","params","grant_type","client_id","client_secret","clientSecret","redirect_uri","response","method","headers","Accept","body","URLSearchParams","toString","ok","text","json","handle","_event$url$searchPara3","_event$url$searchPara2","error_description","errorLoginRedirectPath","Response","trimEnd","errorParams","queryParamsCreate","redirect","createRemoteJWKSet","Promise","all","session","login","ARMOR_REFRESH","ARMOR_LOGIN","ROUTE_PATH_LOGIN","routeLoginFactory","_config$oauth$authori","authorizeEndpoint","randomUUID","response_type","ROUTE_PATH_REDIRECT_LOGOUT","routeRedirectLogoutFactory","logoutEndpoint","logout","ROUTE_PATH_LOGOUT","routeLogoutFactory","_config$oauth$logoutR","returnTo","logoutReturnToParam","armorCreateRefresh","_config$oauth$refresh","refreshEndpoint","refresh","refreshToken","_json$refresh_token","postRefresh","ensureValidToken","fn","validTokens","newTokens","handler","_tokens$exchange","ROUTE_PATH_REFRESH","routeRefreshFactory","getTokens","ex","routeFactories","routeCreate","Map","map","routeFactory","filter","route","cookieSessionGetTokens","cookieSessionLogin","cookieSessionLogout","armorCookieSessionGet","armorCookieSession","armor","routeByPath","resolve","pathname","request","console","log","armorConfigFromOpenId","_body$end_session_end","fetchToUse","global","openIdConfigEndpoint","token_endpoint","authorization_endpoint","jwks_uri","end_session_endpoint"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -15,13 +15,25 @@ function isTokenExchange(value) {
|
|
|
15
15
|
}
|
|
16
16
|
const MINUTES_MS = 60 * 1000;
|
|
17
17
|
function shouldRefresh(tokens) {
|
|
18
|
-
|
|
18
|
+
const accessExpiry = typeof tokens.accessToken !== "string" && tokens.accessToken.exp ? tokens.accessToken.exp : Infinity;
|
|
19
|
+
const expiry = Math.min(tokens.idToken.exp, accessExpiry);
|
|
20
|
+
return expiry < Date.now() + 5 * MINUTES_MS;
|
|
19
21
|
}
|
|
20
22
|
function createExpiresAt(seconds) {
|
|
21
23
|
const now = new Date();
|
|
22
24
|
now.setSeconds(now.getSeconds() + seconds);
|
|
23
25
|
return now;
|
|
24
26
|
}
|
|
27
|
+
function exchangeToTokens(exchange, idToken, accessToken) {
|
|
28
|
+
return {
|
|
29
|
+
exchange,
|
|
30
|
+
idToken: idToken,
|
|
31
|
+
// Generally, IdP's require an audience to get a JWT
|
|
32
|
+
// access token. Most cases, this doesn't matter.
|
|
33
|
+
accessToken: accessToken != null ? accessToken : exchange.access_token,
|
|
34
|
+
expiresAt: createExpiresAt(exchange.expires_in)
|
|
35
|
+
};
|
|
36
|
+
}
|
|
25
37
|
|
|
26
38
|
function jwtIsCompactJwt(token) {
|
|
27
39
|
// Must be three base64url segments
|
|
@@ -177,14 +189,7 @@ const routeRedirectLoginFactory = config => {
|
|
|
177
189
|
const exchange = await exchangeCodeForToken(event.fetch, event.url.origin, code);
|
|
178
190
|
const jwks = jose.createRemoteJWKSet(jwksUrl);
|
|
179
191
|
const [idToken, accessToken] = await Promise.all([jwtVerifyIdToken(config, jwks, exchange.id_token), jwtVerifyAccessToken(config, jwks, exchange.access_token)]);
|
|
180
|
-
await config.session.login(event,
|
|
181
|
-
exchange,
|
|
182
|
-
idToken: idToken,
|
|
183
|
-
// Generally, IdP's require an audience to get a JWT
|
|
184
|
-
// access token. Most cases, this doesn't matter.
|
|
185
|
-
accessToken: accessToken != null ? accessToken : exchange.access_token,
|
|
186
|
-
expiresAt: createExpiresAt(exchange.expires_in)
|
|
187
|
-
});
|
|
192
|
+
await config.session.login(event, exchangeToTokens(exchange, idToken, accessToken));
|
|
188
193
|
throw kit.redirect(302, "/");
|
|
189
194
|
}
|
|
190
195
|
};
|
|
@@ -296,23 +301,31 @@ function armorCreateRefresh(config) {
|
|
|
296
301
|
refresh_token: (_json$refresh_token = json.refresh_token) != null ? _json$refresh_token : refreshToken
|
|
297
302
|
};
|
|
298
303
|
};
|
|
299
|
-
|
|
300
|
-
var _tokens$exchange;
|
|
301
|
-
const refreshToken = (_tokens$exchange = tokens.exchange) == null ? void 0 : _tokens$exchange.refresh_token;
|
|
302
|
-
if (!refreshToken) {
|
|
303
|
-
throw new ArmorRefreshError("Could not find refresh token");
|
|
304
|
-
}
|
|
305
|
-
const newExchange = await refresh(event.fetch, refreshToken);
|
|
304
|
+
const postRefresh = async exchange => {
|
|
306
305
|
const jwks = jose.createRemoteJWKSet(jwksUrl);
|
|
307
|
-
const [idToken, accessToken] = await Promise.all([jwtVerifyIdToken(config, jwks,
|
|
308
|
-
return
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
306
|
+
const [idToken, accessToken] = await Promise.all([jwtVerifyIdToken(config, jwks, exchange.id_token), jwtVerifyAccessToken(config, jwks, exchange.access_token)]);
|
|
307
|
+
return exchangeToTokens(exchange, idToken, accessToken);
|
|
308
|
+
};
|
|
309
|
+
return {
|
|
310
|
+
refresh,
|
|
311
|
+
async ensureValidToken(fetch, tokens, fn) {
|
|
312
|
+
let validTokens = tokens;
|
|
313
|
+
if (shouldRefresh(tokens)) {
|
|
314
|
+
core.throwIfUndefined(tokens.exchange.refresh_token);
|
|
315
|
+
const newTokens = await refresh(fetch, tokens.exchange.refresh_token);
|
|
316
|
+
validTokens = await postRefresh(newTokens);
|
|
317
|
+
}
|
|
318
|
+
return fn(validTokens);
|
|
319
|
+
},
|
|
320
|
+
async handler(event, tokens) {
|
|
321
|
+
var _tokens$exchange;
|
|
322
|
+
const refreshToken = (_tokens$exchange = tokens.exchange) == null ? void 0 : _tokens$exchange.refresh_token;
|
|
323
|
+
if (!refreshToken) {
|
|
324
|
+
throw new ArmorRefreshError("Could not find refresh token");
|
|
325
|
+
}
|
|
326
|
+
const exchange = await refresh(event.fetch, refreshToken);
|
|
327
|
+
return postRefresh(exchange);
|
|
328
|
+
}
|
|
316
329
|
};
|
|
317
330
|
}
|
|
318
331
|
|
|
@@ -332,12 +345,10 @@ const routeRefreshFactory = config => {
|
|
|
332
345
|
}
|
|
333
346
|
const {
|
|
334
347
|
idToken,
|
|
335
|
-
expiresAt,
|
|
336
348
|
accessToken
|
|
337
|
-
} = await refresh(event, tokens);
|
|
349
|
+
} = await refresh.handler(event, tokens);
|
|
338
350
|
return kit.json({
|
|
339
351
|
idToken,
|
|
340
|
-
expiresAt,
|
|
341
352
|
accessToken
|
|
342
353
|
});
|
|
343
354
|
} catch (ex) {
|
|
@@ -409,7 +420,7 @@ function armor(config) {
|
|
|
409
420
|
try {
|
|
410
421
|
if (shouldRefresh(tokens)) {
|
|
411
422
|
console.log("Refreshing token...");
|
|
412
|
-
await refresh(event, tokens);
|
|
423
|
+
await refresh.handler(event, tokens);
|
|
413
424
|
}
|
|
414
425
|
} catch (error) {
|
|
415
426
|
if (error instanceof ArmorRefreshError) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/utils/utils.ts","../src/utils/jwt.ts","../src/utils/cookie.ts","../src/errors.ts","../src/utils/event.ts","../src/routes/redirect-login.ts","../src/browser/index.ts","../src/routes/login.ts","../src/routes/redirect-logout.ts","../src/routes/logout.ts","../src/utils/refresh.ts","../src/routes/refresh.ts","../src/routes/routes.ts","../src/session/cookie.ts","../src/index.ts"],"sourcesContent":["import { strTrimEnd, strTrimStart } from \"@nekm/core\";\nimport type { ArmorTokenExchange, ArmorTokens } from \"../contracts\";\n\nexport function urlConcat(origin: string, path: string): string {\n\treturn [strTrimEnd(origin, \"/\"), strTrimStart(path, \"/\")].join(\"/\");\n}\n\nexport function isTokenExchange(value: unknown): value is ArmorTokenExchange {\n\tif (typeof value !== \"object\" || value === null) return false;\n\n\tconst obj = value as Record<string, unknown>;\n\n\treturn (\n\t\ttypeof obj.access_token === \"string\" &&\n\t\tobj.token_type === \"Bearer\" &&\n\t\ttypeof obj.expires_in === \"number\" &&\n\t\t// Optional fields\n\t\t(typeof obj.id_token === \"string\" || obj.id_token === undefined) &&\n\t\t(typeof obj.refresh_token === \"string\" ||\n\t\t\tobj.refresh_token === undefined) &&\n\t\t(typeof obj.scope === \"string\" || obj.scope === undefined)\n\t);\n}\n\nconst MINUTES_MS = 60 * 1000;\n\nexport function shouldRefresh(tokens: ArmorTokens) {\n\treturn tokens.expiresAt.getTime() < Date.now() + 5 * MINUTES_MS;\n}\n\nexport function createExpiresAt(seconds: number): Date {\n\tconst now = new Date();\n\tnow.setSeconds(now.getSeconds() + seconds);\n\treturn now;\n}\n","import { ArmorConfig } from \"../contracts\";\nimport { JWTPayload, jwtVerify, JWTVerifyGetKey, JWTVerifyOptions } from \"jose\";\nimport { throwIfUndefined } from \"@nekm/core\";\n\nfunction jwtIsCompactJwt(token: string): boolean {\n\t// Must be three base64url segments\n\tconst parts = token.trim().split(\".\");\n\treturn parts.length === 3 && parts.every((p) => p.length > 0);\n}\n\nexport function jwtVerifyIdToken(\n\tconfig: ArmorConfig,\n\tjwks: JWTVerifyGetKey,\n\tidToken: string,\n): Promise<JWTPayload> {\n\tconst payload = jwtVerifyToken(\n\t\tjwks,\n\t\t{\n\t\t\tissuer: config.oauth.issuer,\n\t\t\taudience: config.oauth.clientId,\n\t\t},\n\t\tidToken,\n\t);\n\tthrowIfUndefined(payload);\n\t// @ts-expect-error We're already verifying non-null above.\n\treturn payload;\n}\n\nexport function jwtVerifyAccessToken(\n\tconfig: ArmorConfig,\n\tjwks: JWTVerifyGetKey,\n\taccessToken: string,\n): Promise<JWTPayload | undefined> {\n\tconst opts: JWTVerifyOptions = { issuer: config.oauth.issuer };\n\n\tif (config.oauth.audience) {\n\t\topts.audience = config.oauth.audience;\n\t}\n\n\treturn jwtVerifyToken(jwks, opts, accessToken);\n}\n\nfunction isInvalidCompactJwt(error: unknown): boolean {\n\treturn Boolean(\n\t\ttypeof error === \"object\" &&\n\t\terror &&\n\t\t\"message\" in error &&\n\t\ttypeof error.message === \"string\" &&\n\t\t/invalid compact jws/gi.test(error.message),\n\t);\n}\n\nasync function jwtVerifyToken(\n\tjwks: JWTVerifyGetKey,\n\topts: JWTVerifyOptions,\n\ttoken: string,\n): Promise<JWTPayload | undefined> {\n\ttry {\n\t\tif (!jwtIsCompactJwt(token)) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst { payload } = await jwtVerify(token, jwks, opts);\n\t\treturn payload;\n\t} catch (error) {\n\t\tif (isInvalidCompactJwt(error)) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tthrow error;\n\t}\n}\n","import { Cookies } from \"@sveltejs/kit\";\n\nexport const COOKIE_TOKENS = \"tokens\";\nexport const COOKIE_STATE = \"state\";\n\nconst cookieDeleteOptions = Object.freeze({ path: \"/\" });\n\nconst cookieSetOptions = Object.freeze({\n\t...cookieDeleteOptions,\n\thttpOnly: true,\n\tsecure: true,\n\tsameSite: \"lax\",\n\tmaxAge: 1800, // 30 minutes\n});\n\nexport function cookieSet(\n\tcookies: Cookies,\n\tkey: string,\n\tvalue: string | object,\n) {\n\tcookies.set(key, JSON.stringify(value), cookieSetOptions);\n}\n\nexport function cookieGetAndDelete<T>(\n\tcookies: Cookies,\n\tkey: string,\n): T | undefined {\n\tconst value = cookieGet<T>(cookies, key);\n\n\tif (value) {\n\t\tcookies.delete(key, cookieDeleteOptions);\n\t}\n\n\treturn value;\n}\n\nexport function cookieGet<T>(cookies: Cookies, key: string): T | undefined {\n\tconst value = cookies.get(key);\n\n\treturn !value ? undefined : JSON.parse(value);\n}\n\nexport function cookieDelete(cookies: Cookies, key: string): void {\n\tcookies.delete(key, cookieDeleteOptions);\n}\n","export class ArmorError extends Error {}\nexport class ArmorOpenIdConfigError extends ArmorError {}\nexport class ArmorInvalidStateError extends ArmorError {}\nexport class ArmorAuthMissingError extends ArmorError {}\nexport class ArmorRefreshError extends ArmorError {}\n","import { RequestEvent } from \"@sveltejs/kit\";\nimport { COOKIE_STATE, cookieGetAndDelete } from \"./cookie\";\nimport { ArmorInvalidStateError } from \"../errors\";\n\nexport function eventStateValidOrThrow(event: RequestEvent): void {\n\tconst state = event.url.searchParams.get(\"state\") ?? undefined;\n\tconst stateCookie = cookieGetAndDelete(event.cookies, COOKIE_STATE);\n\n\tif (state !== stateCookie) {\n\t\tthrow new ArmorInvalidStateError();\n\t}\n}\n","import { redirect } from \"@sveltejs/kit\";\nimport type {\n\tArmorConfig,\n\tArmorIdToken,\n\tArmorTokenExchange,\n} from \"../contracts\";\nimport { queryParamsCreate, throwIfUndefined } from \"@nekm/core\";\nimport { createRemoteJWKSet } from \"jose\";\nimport type { RouteFactory } from \"./routes\";\nimport { urlConcat, isTokenExchange, createExpiresAt } from \"../utils/utils\";\nimport { jwtVerifyAccessToken, jwtVerifyIdToken } from \"../utils/jwt\";\nimport { eventStateValidOrThrow } from \"../utils/event\";\n\nexport const ROUTE_PATH_REDIRECT_LOGIN = \"/_armor/redirect/login\";\n\nexport const routeRedirectLoginFactory: RouteFactory = (\n\tconfig: ArmorConfig,\n) => {\n\tconst jwksUrl = new URL(\n\t\tconfig.oauth.jwksEndpoint ??\n\t\t\turlConcat(config.oauth.baseUrl, \".well-known/jwks.json\"),\n\t);\n\n\tconst tokenUrl =\n\t\tconfig.oauth.tokenEndpoint ??\n\t\turlConcat(config.oauth.baseUrl, \"oauth2/token\");\n\n\tconst scope = config.oauth.scope ?? \"openid profile email\";\n\n\tasync function exchangeCodeForToken(\n\t\tfetch: typeof global.fetch,\n\t\torigin: string,\n\t\tcode: string,\n\t): Promise<ArmorTokenExchange> {\n\t\tconst params: Record<string, string> = {\n\t\t\tgrant_type: \"authorization_code\",\n\t\t\tclient_id: config.oauth.clientId,\n\t\t\tclient_secret: config.oauth.clientSecret,\n\t\t\tcode,\n\t\t\tredirect_uri: urlConcat(origin, ROUTE_PATH_REDIRECT_LOGIN),\n\t\t\tscope,\n\t\t};\n\n\t\tif (config.oauth.audience) {\n\t\t\tparams.audience = config.oauth.audience;\n\t\t}\n\n\t\tconst response = await fetch(tokenUrl, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\tAccept: \"application/json\",\n\t\t\t},\n\t\t\tbody: new URLSearchParams(params).toString(),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst error = await response.text();\n\t\t\tthrow new Error(`Token exchange failed: ${error}`);\n\t\t}\n\n\t\tconst token = await response.json();\n\n\t\tif (!isTokenExchange(token)) {\n\t\t\tthrow new Error(\"Response is not a valid token exchange.\");\n\t\t}\n\n\t\treturn token;\n\t}\n\n\treturn {\n\t\tpath: ROUTE_PATH_REDIRECT_LOGIN,\n\t\tmethod: \"GET\",\n\t\tasync handle({ event }) {\n\t\t\teventStateValidOrThrow(event);\n\n\t\t\tconst error = event.url.searchParams.get(\"error\") ?? undefined;\n\n\t\t\tif (error) {\n\t\t\t\tconst error_description =\n\t\t\t\t\tevent.url.searchParams.get(\"error_description\") ?? undefined;\n\n\t\t\t\tif (!config.oauth.errorLoginRedirectPath) {\n\t\t\t\t\treturn new Response(`${error}\\n${error_description}`.trimEnd(), {\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t\"Content-Type\": \"text/plain\",\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst errorParams = queryParamsCreate({ error, error_description });\n\t\t\t\tthrow redirect(\n\t\t\t\t\t302,\n\t\t\t\t\t`${config.oauth.errorLoginRedirectPath}?${errorParams}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst code = event.url.searchParams.get(\"code\") ?? undefined;\n\t\t\tthrowIfUndefined(code);\n\n\t\t\tconst exchange = await exchangeCodeForToken(\n\t\t\t\tevent.fetch,\n\t\t\t\tevent.url.origin,\n\t\t\t\tcode,\n\t\t\t);\n\n\t\t\tconst jwks = createRemoteJWKSet(jwksUrl);\n\n\t\t\tconst [idToken, accessToken] = await Promise.all([\n\t\t\t\tjwtVerifyIdToken(config, jwks, exchange.id_token),\n\t\t\t\tjwtVerifyAccessToken(config, jwks, exchange.access_token),\n\t\t\t]);\n\n\t\t\tawait config.session.login(event, {\n\t\t\t\texchange,\n\t\t\t\tidToken: idToken as ArmorIdToken,\n\t\t\t\t// Generally, IdP's require an audience to get a JWT\n\t\t\t\t// access token. Most cases, this doesn't matter.\n\t\t\t\taccessToken: accessToken ?? exchange.access_token,\n\t\t\t\texpiresAt: createExpiresAt(exchange.expires_in),\n\t\t\t});\n\n\t\t\tthrow redirect(302, \"/\");\n\t\t},\n\t};\n};\n","import { ArmorRefreshError } from \"../errors\";\n\nexport interface ArmorBrowserRefresh {\n\treadonly idToken: string;\n\treadonly accessToken: string;\n\treadonly expiresAt: Date;\n}\n\nexport const ARMOR_REFRESH = \"/_armor/refresh\";\nexport const ARMOR_LOGIN = \"/_armor/login\";\n\nexport async function armorBrowserRefresh(): Promise<ArmorBrowserRefresh> {\n\tconst response = await fetch(ARMOR_REFRESH, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t});\n\n\tif (!response.ok) {\n\t\tif (response.status === 401) {\n\t\t\t// eslint-disable-next-line no-undef\n\t\t\twindow.location.href = ARMOR_LOGIN;\n\t\t\tthrow new ArmorRefreshError(\"Redirecting to login\");\n\t\t}\n\n\t\tconst error = await response.text();\n\t\tthrow new ArmorRefreshError(`Could not refresh token: ${error}`);\n\t}\n\n\treturn response.json();\n}\n","import { redirect } from \"@sveltejs/kit\";\nimport type { ArmorConfig } from \"../contracts\";\nimport { queryParamsCreate } from \"@nekm/core\";\nimport { ROUTE_PATH_REDIRECT_LOGIN } from \"./redirect-login\";\nimport { randomUUID } from \"node:crypto\";\nimport type { RouteFactory } from \"./routes\";\nimport { COOKIE_STATE, cookieSet } from \"../utils/cookie\";\nimport { urlConcat } from \"../utils/utils\";\nimport { ARMOR_LOGIN } from \"../browser\";\n\nexport const ROUTE_PATH_LOGIN = ARMOR_LOGIN;\n\nexport const routeLoginFactory: RouteFactory = (config: ArmorConfig) => {\n\tconst authorizeEndpoint =\n\t\tconfig.oauth.authorizeEndpoint ??\n\t\turlConcat(config.oauth.baseUrl, \"oauth2/authorize\");\n\n\tconst scope = config.oauth.scope ?? \"openid profile email\";\n\n\treturn {\n\t\tpath: ROUTE_PATH_LOGIN,\n\t\tmethod: \"GET\",\n\t\tasync handle({ event }) {\n\t\t\tconst state = randomUUID();\n\t\t\tcookieSet(event.cookies, COOKIE_STATE, state);\n\n\t\t\tconst params = queryParamsCreate({\n\t\t\t\tclient_id: config.oauth.clientId,\n\t\t\t\tresponse_type: \"code\",\n\t\t\t\tredirect_uri: urlConcat(event.url.origin, ROUTE_PATH_REDIRECT_LOGIN),\n\t\t\t\tstate,\n\t\t\t\tscope,\n\t\t\t\taudience: config.oauth.audience,\n\t\t\t});\n\n\t\t\tthrow redirect(302, `${authorizeEndpoint}?${params}`);\n\t\t},\n\t};\n};\n","import { redirect } from \"@sveltejs/kit\";\nimport type { ArmorConfig } from \"../contracts\";\nimport type { RouteFactory } from \"./routes\";\nimport { eventStateValidOrThrow } from \"../utils/event\";\n\nexport const ROUTE_PATH_REDIRECT_LOGOUT = \"/_armor/redirect/logout\";\n\nexport const routeRedirectLogoutFactory: RouteFactory = (\n\tconfig: ArmorConfig,\n) => {\n\t// Check if the oauth provider supports a logout path.\n\tif (!config.oauth.logoutEndpoint) {\n\t\treturn undefined;\n\t}\n\n\treturn {\n\t\tpath: ROUTE_PATH_REDIRECT_LOGOUT,\n\t\tmethod: \"GET\",\n\t\tasync handle({ event }) {\n\t\t\teventStateValidOrThrow(event);\n\n\t\t\tawait config.session.logout(event);\n\n\t\t\tthrow redirect(302, \"/\");\n\t\t},\n\t};\n};\n","import { redirect } from \"@sveltejs/kit\";\nimport type { ArmorConfig } from \"../contracts\";\nimport { queryParamsCreate } from \"@nekm/core\";\nimport { ROUTE_PATH_REDIRECT_LOGOUT } from \"./redirect-logout\";\nimport type { RouteFactory } from \"./routes\";\nimport { urlConcat } from \"../utils/utils\";\nimport { randomUUID } from \"node:crypto\";\nimport { COOKIE_STATE, cookieSet } from \"../utils/cookie\";\n\nexport const ROUTE_PATH_LOGOUT = \"/_armor/logout\";\n\nexport const routeLogoutFactory: RouteFactory = (config: ArmorConfig) => {\n\t// Check if the oauth provider supports a logout path.\n\tif (!config.oauth.logoutEndpoint) {\n\t\treturn undefined;\n\t}\n\n\tconst returnTo = config.oauth.logoutReturnToParam ?? \"logout_uri\";\n\n\treturn {\n\t\tpath: ROUTE_PATH_LOGOUT,\n\t\tmethod: \"GET\",\n\t\tasync handle({ event }) {\n\t\t\tconst state = randomUUID();\n\t\t\tcookieSet(event.cookies, COOKIE_STATE, state);\n\n\t\t\tconst params = queryParamsCreate({\n\t\t\t\t[returnTo]: urlConcat(event.url.origin, ROUTE_PATH_REDIRECT_LOGOUT),\n\t\t\t\tclient_id: config.oauth.clientId,\n\t\t\t\tstate,\n\t\t\t});\n\n\t\t\tthrow redirect(302, `${config.oauth.logoutEndpoint}?${params}`);\n\t\t},\n\t};\n};\n","import { createRemoteJWKSet } from \"jose\";\nimport {\n\tArmorConfig,\n\tArmorIdToken,\n\tArmorTokenExchange,\n\tArmorTokens,\n} from \"../contracts\";\nimport { ArmorRefreshError } from \"../errors\";\nimport { createExpiresAt, urlConcat } from \"./utils\";\nimport { jwtVerifyAccessToken, jwtVerifyIdToken } from \"./jwt\";\nimport { RequestEvent } from \"@sveltejs/kit\";\n\nexport function armorCreateRefresh(config: ArmorConfig) {\n\tconst refreshEndpoint =\n\t\tconfig.oauth.refreshEndpoint ??\n\t\turlConcat(config.oauth.baseUrl, \"oauth2/token\");\n\n\tconst jwksUrl = new URL(\n\t\tconfig.oauth.jwksEndpoint ??\n\t\t\turlConcat(config.oauth.baseUrl, \".well-known/jwks.json\"),\n\t);\n\n\tconst refresh = async (\n\t\tfetch: typeof global.fetch,\n\t\trefreshToken: string,\n\t): Promise<ArmorTokenExchange> => {\n\t\tconst body = new URLSearchParams({\n\t\t\tgrant_type: \"refresh_token\",\n\t\t\tclient_id: config.oauth.clientId,\n\t\t\tclient_secret: config.oauth.clientSecret,\n\t\t\trefresh_token: refreshToken,\n\t\t});\n\n\t\tif (config.oauth.scope) {\n\t\t\tbody.set(\"scope\", config.oauth.scope);\n\t\t}\n\n\t\tconst response = await fetch(refreshEndpoint, {\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\tAccept: \"application/json\",\n\t\t\t},\n\t\t\tbody: body.toString(),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst error = await response.text();\n\t\t\tthrow new ArmorRefreshError(`Could not refresh token: ${error}`);\n\t\t}\n\n\t\tconst json: ArmorTokenExchange = await response.json();\n\n\t\treturn {\n\t\t\t...json,\n\t\t\trefresh_token: json.refresh_token ?? refreshToken,\n\t\t};\n\t};\n\n\treturn async (\n\t\tevent: RequestEvent,\n\t\ttokens: ArmorTokens,\n\t): Promise<ArmorTokens> => {\n\t\tconst refreshToken = tokens.exchange?.refresh_token;\n\n\t\tif (!refreshToken) {\n\t\t\tthrow new ArmorRefreshError(\"Could not find refresh token\");\n\t\t}\n\n\t\tconst newExchange = await refresh(event.fetch, refreshToken);\n\n\t\tconst jwks = createRemoteJWKSet(jwksUrl);\n\n\t\tconst [idToken, accessToken] = await Promise.all([\n\t\t\tjwtVerifyIdToken(config, jwks, newExchange.id_token),\n\t\t\tjwtVerifyAccessToken(config, jwks, newExchange.access_token),\n\t\t]);\n\n\t\treturn {\n\t\t\texchange: newExchange,\n\t\t\tidToken: idToken as ArmorIdToken,\n\t\t\t// Generally, IdP's require an audience to get a JWT\n\t\t\t// access token. Most cases, this doesn't matter.\n\t\t\taccessToken: accessToken ?? newExchange.access_token,\n\t\t\texpiresAt: createExpiresAt(newExchange.expires_in),\n\t\t};\n\t};\n}\n","import { error, json } from \"@sveltejs/kit\";\nimport type { ArmorConfig } from \"../contracts\";\nimport type { RouteFactory } from \"./routes\";\nimport { armorCreateRefresh } from \"../utils/refresh\";\nimport { ARMOR_REFRESH } from \"../browser\";\nimport { ArmorRefreshError } from \"../errors\";\n\nexport const ROUTE_PATH_REFRESH = ARMOR_REFRESH;\n\nexport const routeRefreshFactory: RouteFactory = (config: ArmorConfig) => {\n\tconst refresh = armorCreateRefresh(config);\n\n\treturn {\n\t\tpath: ROUTE_PATH_REFRESH,\n\t\tmethod: \"POST\",\n\t\tasync handle({ event }) {\n\t\t\ttry {\n\t\t\t\tconst tokens = await config.session.getTokens(event);\n\n\t\t\t\tif (!tokens) {\n\t\t\t\t\treturn error(401, \"Unauthorized\");\n\t\t\t\t}\n\n\t\t\t\tconst { idToken, expiresAt, accessToken } = await refresh(\n\t\t\t\t\tevent,\n\t\t\t\t\ttokens,\n\t\t\t\t);\n\n\t\t\t\treturn json({ idToken, expiresAt, accessToken });\n\t\t\t} catch (ex) {\n\t\t\t\tif (ex instanceof ArmorRefreshError) {\n\t\t\t\t\treturn error(401, \"Unauthorized\");\n\t\t\t\t}\n\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t},\n\t};\n};\n","import type { Handle } from \"@sveltejs/kit\";\nimport type { ArmorConfig } from \"../contracts\";\nimport { routeLoginFactory } from \"./login\";\nimport { routeLogoutFactory } from \"./logout\";\nimport { routeRedirectLogoutFactory } from \"./redirect-logout\";\nimport { routeRedirectLoginFactory } from \"./redirect-login\";\nimport { routeRefreshFactory } from \"./refresh\";\n\nexport interface Route {\n\treadonly path: string;\n\treadonly handle: Handle;\n\treadonly method: \"GET\" | \"POST\";\n}\n\nexport type RouteFactory = (config: ArmorConfig) => Route | undefined;\n\nconst routeFactories = Object.freeze([\n\trouteLoginFactory,\n\trouteLogoutFactory,\n\trouteRedirectLoginFactory,\n\trouteRedirectLogoutFactory,\n\trouteRefreshFactory,\n]);\n\nexport function routeCreate(config: ArmorConfig): Map<string, Route> {\n\t// @ts-expect-error Incorrect typing error.\n\treturn new Map(\n\t\trouteFactories\n\t\t\t.map((routeFactory) => routeFactory(config))\n\t\t\t.filter((route) => Boolean(route))\n\t\t\t// @ts-expect-error Incorrect typing error.\n\t\t\t.map((route) => [route.path, route]),\n\t);\n}\n","import { RequestEvent } from \"@sveltejs/kit\";\nimport {\n\tCOOKIE_TOKENS,\n\tcookieDelete,\n\tcookieGet,\n\tcookieSet,\n} from \"../utils/cookie\";\nimport { ArmorConfig, ArmorTokens } from \"../contracts\";\nimport { ArmorAuthMissingError } from \"../errors\";\n\nfunction cookieSessionGetTokens({\n\tcookies,\n}: RequestEvent): ArmorTokens | undefined {\n\treturn cookies.get(COOKIE_TOKENS) as ArmorTokens | undefined;\n}\n\nexport function cookieSessionLogin(\n\t{ cookies }: RequestEvent,\n\ttokens: ArmorTokens,\n): void {\n\tcookieSet(cookies, COOKIE_TOKENS, tokens);\n}\n\nfunction cookieSessionLogout({ cookies }: RequestEvent): void {\n\tcookieDelete(cookies, COOKIE_TOKENS);\n}\n\nexport function armorCookieSessionGet({ cookies }: RequestEvent): ArmorTokens {\n\tconst tokens = cookieGet<ArmorTokens>(cookies, COOKIE_TOKENS);\n\n\tif (!tokens) {\n\t\tthrow new ArmorAuthMissingError();\n\t}\n\n\treturn tokens;\n}\n\nexport const armorCookieSession: ArmorConfig[\"session\"] = {\n\tgetTokens: cookieSessionGetTokens,\n\tlogin: cookieSessionLogin,\n\tlogout: cookieSessionLogout,\n};\n","import { redirect, type Handle } from \"@sveltejs/kit\";\nimport { ROUTE_PATH_LOGIN } from \"./routes/login\";\nimport type { ArmorConfig, ArmorOpenIdConfig, ArmorTokens } from \"./contracts\";\nimport { routeCreate } from \"./routes/routes\";\nimport { ArmorOpenIdConfigError, ArmorRefreshError } from \"./errors\";\nimport { shouldRefresh } from \"./utils/utils\";\nimport { armorCreateRefresh } from \"./utils/refresh\";\n\nexport type { ArmorConfig, ArmorTokens };\nexport { armorCookieSession, armorCookieSessionGet } from \"./session/cookie\";\nexport { armorCreateRefresh } from \"./utils/refresh\";\n\nexport function armor(config: ArmorConfig): Handle {\n\tconst routeByPath = routeCreate(config);\n\tconst refresh = armorCreateRefresh(config);\n\n\treturn async ({ event, resolve }) => {\n\t\tconst route = routeByPath.get(event.url.pathname);\n\n\t\tif (route && route.method === event.request.method) {\n\t\t\treturn route.handle({ event, resolve });\n\t\t}\n\n\t\tconst tokens = await config.session.getTokens(event);\n\n\t\tif (!tokens) {\n\t\t\tthrow redirect(302, ROUTE_PATH_LOGIN);\n\t\t}\n\n\t\ttry {\n\t\t\tif (shouldRefresh(tokens)) {\n\t\t\t\tconsole.log(\"Refreshing token...\");\n\t\t\t\tawait refresh(event, tokens);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (error instanceof ArmorRefreshError) {\n\t\t\t\tconsole.error(\"Could not refresh token. Redirect user to login...\");\n\t\t\t\tthrow redirect(302, ROUTE_PATH_LOGIN);\n\t\t\t}\n\n\t\t\tthrow error;\n\t\t}\n\n\t\treturn resolve(event);\n\t};\n}\n\n/**\n * Some IdP's expose a /.well-known/openid-configuration that specifies how to configure.\n * Use that to create your config.\n * @param config\n * @param fetch\n */\nexport async function armorConfigFromOpenId(\n\tconfig: ArmorOpenIdConfig,\n\tfetch?: typeof global.fetch,\n): Promise<ArmorConfig> {\n\tconst fetchToUse = fetch ?? global.fetch;\n\n\tconst response = await fetchToUse(config.oauth.openIdConfigEndpoint, {\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t});\n\n\tif (!response.ok) {\n\t\tconst text = await response.text();\n\t\tthrow new ArmorOpenIdConfigError(text);\n\t}\n\n\tconst body = await response.json();\n\n\treturn {\n\t\t...config,\n\t\toauth: {\n\t\t\t...config.oauth,\n\t\t\ttokenEndpoint: body.token_endpoint,\n\t\t\tauthorizeEndpoint: body.authorization_endpoint,\n\t\t\tissuer: body.issuer,\n\t\t\tjwksEndpoint: body.jwks_uri,\n\t\t\tlogoutEndpoint: body.end_session_endpoint ?? undefined,\n\t\t\trefreshEndpoint: body.token_endpoint,\n\t\t},\n\t};\n}\n"],"names":["urlConcat","origin","path","strTrimEnd","strTrimStart","join","isTokenExchange","value","obj","access_token","token_type","expires_in","id_token","undefined","refresh_token","scope","MINUTES_MS","shouldRefresh","tokens","expiresAt","getTime","Date","now","createExpiresAt","seconds","setSeconds","getSeconds","jwtIsCompactJwt","token","parts","trim","split","length","every","p","jwtVerifyIdToken","config","jwks","idToken","payload","jwtVerifyToken","issuer","oauth","audience","clientId","throwIfUndefined","jwtVerifyAccessToken","accessToken","opts","isInvalidCompactJwt","error","Boolean","message","test","jwtVerify","COOKIE_TOKENS","COOKIE_STATE","cookieDeleteOptions","Object","freeze","cookieSetOptions","httpOnly","secure","sameSite","maxAge","cookieSet","cookies","key","set","JSON","stringify","cookieGetAndDelete","cookieGet","delete","get","parse","cookieDelete","ArmorError","Error","ArmorOpenIdConfigError","ArmorInvalidStateError","ArmorAuthMissingError","ArmorRefreshError","eventStateValidOrThrow","event","_event$url$searchPara","state","url","searchParams","stateCookie","ROUTE_PATH_REDIRECT_LOGIN","routeRedirectLoginFactory","_config$oauth$jwksEnd","_config$oauth$tokenEn","_config$oauth$scope","jwksUrl","URL","jwksEndpoint","baseUrl","tokenUrl","tokenEndpoint","exchangeCodeForToken","fetch","code","params","grant_type","client_id","client_secret","clientSecret","redirect_uri","response","method","headers","Accept","body","URLSearchParams","toString","ok","text","json","handle","_event$url$searchPara3","_event$url$searchPara2","error_description","errorLoginRedirectPath","Response","trimEnd","errorParams","queryParamsCreate","redirect","exchange","createRemoteJWKSet","Promise","all","session","login","ARMOR_REFRESH","ARMOR_LOGIN","ROUTE_PATH_LOGIN","routeLoginFactory","_config$oauth$authori","authorizeEndpoint","randomUUID","response_type","ROUTE_PATH_REDIRECT_LOGOUT","routeRedirectLogoutFactory","logoutEndpoint","logout","ROUTE_PATH_LOGOUT","routeLogoutFactory","_config$oauth$logoutR","returnTo","logoutReturnToParam","armorCreateRefresh","_config$oauth$refresh","refreshEndpoint","refresh","refreshToken","_json$refresh_token","_tokens$exchange","newExchange","ROUTE_PATH_REFRESH","routeRefreshFactory","getTokens","ex","routeFactories","routeCreate","Map","map","routeFactory","filter","route","cookieSessionGetTokens","cookieSessionLogin","cookieSessionLogout","armorCookieSessionGet","armorCookieSession","armor","routeByPath","resolve","pathname","request","console","log","armorConfigFromOpenId","_body$end_session_end","fetchToUse","global","openIdConfigEndpoint","token_endpoint","authorization_endpoint","jwks_uri","end_session_endpoint"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/utils/utils.ts","../src/utils/jwt.ts","../src/utils/cookie.ts","../src/errors.ts","../src/utils/event.ts","../src/routes/redirect-login.ts","../src/browser/index.ts","../src/routes/login.ts","../src/routes/redirect-logout.ts","../src/routes/logout.ts","../src/utils/refresh.ts","../src/routes/refresh.ts","../src/routes/routes.ts","../src/session/cookie.ts","../src/index.ts"],"sourcesContent":["import { strTrimEnd, strTrimStart } from \"@nekm/core\";\nimport type {\n\tArmorAccessToken,\n\tArmorIdToken,\n\tArmorTokenExchange,\n\tArmorTokens,\n} from \"../contracts\";\n\nexport function urlConcat(origin: string, path: string): string {\n\treturn [strTrimEnd(origin, \"/\"), strTrimStart(path, \"/\")].join(\"/\");\n}\n\nexport function isTokenExchange(value: unknown): value is ArmorTokenExchange {\n\tif (typeof value !== \"object\" || value === null) return false;\n\n\tconst obj = value as Record<string, unknown>;\n\n\treturn (\n\t\ttypeof obj.access_token === \"string\" &&\n\t\tobj.token_type === \"Bearer\" &&\n\t\ttypeof obj.expires_in === \"number\" &&\n\t\t// Optional fields\n\t\t(typeof obj.id_token === \"string\" || obj.id_token === undefined) &&\n\t\t(typeof obj.refresh_token === \"string\" ||\n\t\t\tobj.refresh_token === undefined) &&\n\t\t(typeof obj.scope === \"string\" || obj.scope === undefined)\n\t);\n}\n\nconst MINUTES_MS = 60 * 1000;\n\nexport function shouldRefresh(\n\ttokens: Pick<ArmorTokens, \"idToken\" | \"accessToken\">,\n): boolean {\n\tconst accessExpiry =\n\t\ttypeof tokens.accessToken !== \"string\" && tokens.accessToken.exp\n\t\t\t? tokens.accessToken.exp\n\t\t\t: Infinity;\n\tconst expiry = Math.min(tokens.idToken.exp, accessExpiry);\n\n\treturn expiry < Date.now() + 5 * MINUTES_MS;\n}\n\nexport function createExpiresAt(seconds: number): Date {\n\tconst now = new Date();\n\tnow.setSeconds(now.getSeconds() + seconds);\n\treturn now;\n}\n\nexport function exchangeToTokens(\n\texchange: ArmorTokenExchange,\n\tidToken: ArmorIdToken,\n\taccessToken?: ArmorAccessToken,\n): ArmorTokens {\n\treturn {\n\t\texchange,\n\t\tidToken: idToken as ArmorIdToken,\n\t\t// Generally, IdP's require an audience to get a JWT\n\t\t// access token. Most cases, this doesn't matter.\n\t\taccessToken: accessToken ?? exchange.access_token,\n\t\texpiresAt: createExpiresAt(exchange.expires_in),\n\t};\n}\n","import { ArmorConfig } from \"../contracts\";\nimport { JWTPayload, jwtVerify, JWTVerifyGetKey, JWTVerifyOptions } from \"jose\";\nimport { throwIfUndefined } from \"@nekm/core\";\n\nfunction jwtIsCompactJwt(token: string): boolean {\n\t// Must be three base64url segments\n\tconst parts = token.trim().split(\".\");\n\treturn parts.length === 3 && parts.every((p) => p.length > 0);\n}\n\nexport function jwtVerifyIdToken(\n\tconfig: ArmorConfig,\n\tjwks: JWTVerifyGetKey,\n\tidToken: string,\n): Promise<JWTPayload> {\n\tconst payload = jwtVerifyToken(\n\t\tjwks,\n\t\t{\n\t\t\tissuer: config.oauth.issuer,\n\t\t\taudience: config.oauth.clientId,\n\t\t},\n\t\tidToken,\n\t);\n\tthrowIfUndefined(payload);\n\t// @ts-expect-error We're already verifying non-null above.\n\treturn payload;\n}\n\nexport function jwtVerifyAccessToken(\n\tconfig: ArmorConfig,\n\tjwks: JWTVerifyGetKey,\n\taccessToken: string,\n): Promise<JWTPayload | undefined> {\n\tconst opts: JWTVerifyOptions = { issuer: config.oauth.issuer };\n\n\tif (config.oauth.audience) {\n\t\topts.audience = config.oauth.audience;\n\t}\n\n\treturn jwtVerifyToken(jwks, opts, accessToken);\n}\n\nfunction isInvalidCompactJwt(error: unknown): boolean {\n\treturn Boolean(\n\t\ttypeof error === \"object\" &&\n\t\terror &&\n\t\t\"message\" in error &&\n\t\ttypeof error.message === \"string\" &&\n\t\t/invalid compact jws/gi.test(error.message),\n\t);\n}\n\nasync function jwtVerifyToken(\n\tjwks: JWTVerifyGetKey,\n\topts: JWTVerifyOptions,\n\ttoken: string,\n): Promise<JWTPayload | undefined> {\n\ttry {\n\t\tif (!jwtIsCompactJwt(token)) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst { payload } = await jwtVerify(token, jwks, opts);\n\t\treturn payload;\n\t} catch (error) {\n\t\tif (isInvalidCompactJwt(error)) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tthrow error;\n\t}\n}\n","import { Cookies } from \"@sveltejs/kit\";\n\nexport const COOKIE_TOKENS = \"tokens\";\nexport const COOKIE_STATE = \"state\";\n\nconst cookieDeleteOptions = Object.freeze({ path: \"/\" });\n\nconst cookieSetOptions = Object.freeze({\n\t...cookieDeleteOptions,\n\thttpOnly: true,\n\tsecure: true,\n\tsameSite: \"lax\",\n\tmaxAge: 1800, // 30 minutes\n});\n\nexport function cookieSet(\n\tcookies: Cookies,\n\tkey: string,\n\tvalue: string | object,\n) {\n\tcookies.set(key, JSON.stringify(value), cookieSetOptions);\n}\n\nexport function cookieGetAndDelete<T>(\n\tcookies: Cookies,\n\tkey: string,\n): T | undefined {\n\tconst value = cookieGet<T>(cookies, key);\n\n\tif (value) {\n\t\tcookies.delete(key, cookieDeleteOptions);\n\t}\n\n\treturn value;\n}\n\nexport function cookieGet<T>(cookies: Cookies, key: string): T | undefined {\n\tconst value = cookies.get(key);\n\n\treturn !value ? undefined : JSON.parse(value);\n}\n\nexport function cookieDelete(cookies: Cookies, key: string): void {\n\tcookies.delete(key, cookieDeleteOptions);\n}\n","export class ArmorError extends Error {}\nexport class ArmorOpenIdConfigError extends ArmorError {}\nexport class ArmorInvalidStateError extends ArmorError {}\nexport class ArmorAuthMissingError extends ArmorError {}\nexport class ArmorRefreshError extends ArmorError {}\n","import { RequestEvent } from \"@sveltejs/kit\";\nimport { COOKIE_STATE, cookieGetAndDelete } from \"./cookie\";\nimport { ArmorInvalidStateError } from \"../errors\";\n\nexport function eventStateValidOrThrow(event: RequestEvent): void {\n\tconst state = event.url.searchParams.get(\"state\") ?? undefined;\n\tconst stateCookie = cookieGetAndDelete(event.cookies, COOKIE_STATE);\n\n\tif (state !== stateCookie) {\n\t\tthrow new ArmorInvalidStateError();\n\t}\n}\n","import { redirect } from \"@sveltejs/kit\";\nimport type {\n\tArmorConfig,\n\tArmorIdToken,\n\tArmorTokenExchange,\n} from \"../contracts\";\nimport { queryParamsCreate, throwIfUndefined } from \"@nekm/core\";\nimport { createRemoteJWKSet } from \"jose\";\nimport type { RouteFactory } from \"./routes\";\nimport { urlConcat, isTokenExchange, exchangeToTokens } from \"../utils/utils\";\nimport { jwtVerifyAccessToken, jwtVerifyIdToken } from \"../utils/jwt\";\nimport { eventStateValidOrThrow } from \"../utils/event\";\n\nexport const ROUTE_PATH_REDIRECT_LOGIN = \"/_armor/redirect/login\";\n\nexport const routeRedirectLoginFactory: RouteFactory = (\n\tconfig: ArmorConfig,\n) => {\n\tconst jwksUrl = new URL(\n\t\tconfig.oauth.jwksEndpoint ??\n\t\t\turlConcat(config.oauth.baseUrl, \".well-known/jwks.json\"),\n\t);\n\n\tconst tokenUrl =\n\t\tconfig.oauth.tokenEndpoint ??\n\t\turlConcat(config.oauth.baseUrl, \"oauth2/token\");\n\n\tconst scope = config.oauth.scope ?? \"openid profile email\";\n\n\tasync function exchangeCodeForToken(\n\t\tfetch: typeof global.fetch,\n\t\torigin: string,\n\t\tcode: string,\n\t): Promise<ArmorTokenExchange> {\n\t\tconst params: Record<string, string> = {\n\t\t\tgrant_type: \"authorization_code\",\n\t\t\tclient_id: config.oauth.clientId,\n\t\t\tclient_secret: config.oauth.clientSecret,\n\t\t\tcode,\n\t\t\tredirect_uri: urlConcat(origin, ROUTE_PATH_REDIRECT_LOGIN),\n\t\t\tscope,\n\t\t};\n\n\t\tif (config.oauth.audience) {\n\t\t\tparams.audience = config.oauth.audience;\n\t\t}\n\n\t\tconst response = await fetch(tokenUrl, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\tAccept: \"application/json\",\n\t\t\t},\n\t\t\tbody: new URLSearchParams(params).toString(),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst error = await response.text();\n\t\t\tthrow new Error(`Token exchange failed: ${error}`);\n\t\t}\n\n\t\tconst token = await response.json();\n\n\t\tif (!isTokenExchange(token)) {\n\t\t\tthrow new Error(\"Response is not a valid token exchange.\");\n\t\t}\n\n\t\treturn token;\n\t}\n\n\treturn {\n\t\tpath: ROUTE_PATH_REDIRECT_LOGIN,\n\t\tmethod: \"GET\",\n\t\tasync handle({ event }) {\n\t\t\teventStateValidOrThrow(event);\n\n\t\t\tconst error = event.url.searchParams.get(\"error\") ?? undefined;\n\n\t\t\tif (error) {\n\t\t\t\tconst error_description =\n\t\t\t\t\tevent.url.searchParams.get(\"error_description\") ?? undefined;\n\n\t\t\t\tif (!config.oauth.errorLoginRedirectPath) {\n\t\t\t\t\treturn new Response(`${error}\\n${error_description}`.trimEnd(), {\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t\"Content-Type\": \"text/plain\",\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst errorParams = queryParamsCreate({ error, error_description });\n\t\t\t\tthrow redirect(\n\t\t\t\t\t302,\n\t\t\t\t\t`${config.oauth.errorLoginRedirectPath}?${errorParams}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst code = event.url.searchParams.get(\"code\") ?? undefined;\n\t\t\tthrowIfUndefined(code);\n\n\t\t\tconst exchange = await exchangeCodeForToken(\n\t\t\t\tevent.fetch,\n\t\t\t\tevent.url.origin,\n\t\t\t\tcode,\n\t\t\t);\n\n\t\t\tconst jwks = createRemoteJWKSet(jwksUrl);\n\n\t\t\tconst [idToken, accessToken] = await Promise.all([\n\t\t\t\tjwtVerifyIdToken(config, jwks, exchange.id_token),\n\t\t\t\tjwtVerifyAccessToken(config, jwks, exchange.access_token),\n\t\t\t]);\n\n\t\t\tawait config.session.login(\n\t\t\t\tevent,\n\t\t\t\texchangeToTokens(exchange, idToken as ArmorIdToken, accessToken),\n\t\t\t);\n\n\t\t\tthrow redirect(302, \"/\");\n\t\t},\n\t};\n};\n","import { ArmorTokens } from \"../contracts\";\nimport { ArmorRefreshError } from \"../errors\";\nimport { shouldRefresh } from \"../utils/utils\";\n\nexport const ARMOR_REFRESH = \"/_armor/refresh\";\nexport const ARMOR_LOGIN = \"/_armor/login\";\n\ntype ArmorBrowserTokens = Pick<ArmorTokens, \"idToken\" | \"accessToken\">;\n\nexport async function armorBrowserRefresh(): Promise<ArmorBrowserTokens> {\n\tconst response = await fetch(ARMOR_REFRESH, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t});\n\n\tif (!response.ok) {\n\t\tif (response.status === 401) {\n\t\t\t// eslint-disable-next-line no-undef\n\t\t\twindow.location.href = ARMOR_LOGIN;\n\t\t\tthrow new ArmorRefreshError(\"Redirecting to login\");\n\t\t}\n\n\t\tconst error = await response.text();\n\t\tthrow new ArmorRefreshError(`Could not refresh token: ${error}`);\n\t}\n\n\treturn response.json();\n}\n\nexport async function armorBrowserEnsureValidTokens<T>(\n\ttokens: ArmorBrowserTokens,\n\tfn: (tokens: ArmorBrowserTokens) => T | Promise<T>,\n): Promise<T> {\n\tconst validTokens = shouldRefresh(tokens)\n\t\t? await armorBrowserRefresh()\n\t\t: tokens;\n\n\treturn fn(validTokens);\n}\n","import { redirect } from \"@sveltejs/kit\";\nimport type { ArmorConfig } from \"../contracts\";\nimport { queryParamsCreate } from \"@nekm/core\";\nimport { ROUTE_PATH_REDIRECT_LOGIN } from \"./redirect-login\";\nimport { randomUUID } from \"node:crypto\";\nimport type { RouteFactory } from \"./routes\";\nimport { COOKIE_STATE, cookieSet } from \"../utils/cookie\";\nimport { urlConcat } from \"../utils/utils\";\nimport { ARMOR_LOGIN } from \"../browser\";\n\nexport const ROUTE_PATH_LOGIN = ARMOR_LOGIN;\n\nexport const routeLoginFactory: RouteFactory = (config: ArmorConfig) => {\n\tconst authorizeEndpoint =\n\t\tconfig.oauth.authorizeEndpoint ??\n\t\turlConcat(config.oauth.baseUrl, \"oauth2/authorize\");\n\n\tconst scope = config.oauth.scope ?? \"openid profile email\";\n\n\treturn {\n\t\tpath: ROUTE_PATH_LOGIN,\n\t\tmethod: \"GET\",\n\t\tasync handle({ event }) {\n\t\t\tconst state = randomUUID();\n\t\t\tcookieSet(event.cookies, COOKIE_STATE, state);\n\n\t\t\tconst params = queryParamsCreate({\n\t\t\t\tclient_id: config.oauth.clientId,\n\t\t\t\tresponse_type: \"code\",\n\t\t\t\tredirect_uri: urlConcat(event.url.origin, ROUTE_PATH_REDIRECT_LOGIN),\n\t\t\t\tstate,\n\t\t\t\tscope,\n\t\t\t\taudience: config.oauth.audience,\n\t\t\t});\n\n\t\t\tthrow redirect(302, `${authorizeEndpoint}?${params}`);\n\t\t},\n\t};\n};\n","import { redirect } from \"@sveltejs/kit\";\nimport type { ArmorConfig } from \"../contracts\";\nimport type { RouteFactory } from \"./routes\";\nimport { eventStateValidOrThrow } from \"../utils/event\";\n\nexport const ROUTE_PATH_REDIRECT_LOGOUT = \"/_armor/redirect/logout\";\n\nexport const routeRedirectLogoutFactory: RouteFactory = (\n\tconfig: ArmorConfig,\n) => {\n\t// Check if the oauth provider supports a logout path.\n\tif (!config.oauth.logoutEndpoint) {\n\t\treturn undefined;\n\t}\n\n\treturn {\n\t\tpath: ROUTE_PATH_REDIRECT_LOGOUT,\n\t\tmethod: \"GET\",\n\t\tasync handle({ event }) {\n\t\t\teventStateValidOrThrow(event);\n\n\t\t\tawait config.session.logout(event);\n\n\t\t\tthrow redirect(302, \"/\");\n\t\t},\n\t};\n};\n","import { redirect } from \"@sveltejs/kit\";\nimport type { ArmorConfig } from \"../contracts\";\nimport { queryParamsCreate } from \"@nekm/core\";\nimport { ROUTE_PATH_REDIRECT_LOGOUT } from \"./redirect-logout\";\nimport type { RouteFactory } from \"./routes\";\nimport { urlConcat } from \"../utils/utils\";\nimport { randomUUID } from \"node:crypto\";\nimport { COOKIE_STATE, cookieSet } from \"../utils/cookie\";\n\nexport const ROUTE_PATH_LOGOUT = \"/_armor/logout\";\n\nexport const routeLogoutFactory: RouteFactory = (config: ArmorConfig) => {\n\t// Check if the oauth provider supports a logout path.\n\tif (!config.oauth.logoutEndpoint) {\n\t\treturn undefined;\n\t}\n\n\tconst returnTo = config.oauth.logoutReturnToParam ?? \"logout_uri\";\n\n\treturn {\n\t\tpath: ROUTE_PATH_LOGOUT,\n\t\tmethod: \"GET\",\n\t\tasync handle({ event }) {\n\t\t\tconst state = randomUUID();\n\t\t\tcookieSet(event.cookies, COOKIE_STATE, state);\n\n\t\t\tconst params = queryParamsCreate({\n\t\t\t\t[returnTo]: urlConcat(event.url.origin, ROUTE_PATH_REDIRECT_LOGOUT),\n\t\t\t\tclient_id: config.oauth.clientId,\n\t\t\t\tstate,\n\t\t\t});\n\n\t\t\tthrow redirect(302, `${config.oauth.logoutEndpoint}?${params}`);\n\t\t},\n\t};\n};\n","import { createRemoteJWKSet } from \"jose\";\nimport {\n\tArmorConfig,\n\tArmorIdToken,\n\tArmorTokenExchange,\n\tArmorTokens,\n} from \"../contracts\";\nimport { ArmorRefreshError } from \"../errors\";\nimport { exchangeToTokens, shouldRefresh, urlConcat } from \"./utils\";\nimport { jwtVerifyAccessToken, jwtVerifyIdToken } from \"./jwt\";\nimport { RequestEvent } from \"@sveltejs/kit\";\nimport { throwIfUndefined } from \"@nekm/core\";\n\nexport function armorCreateRefresh(config: ArmorConfig) {\n\tconst refreshEndpoint =\n\t\tconfig.oauth.refreshEndpoint ??\n\t\turlConcat(config.oauth.baseUrl, \"oauth2/token\");\n\n\tconst jwksUrl = new URL(\n\t\tconfig.oauth.jwksEndpoint ??\n\t\t\turlConcat(config.oauth.baseUrl, \".well-known/jwks.json\"),\n\t);\n\n\tconst refresh = async (\n\t\tfetch: typeof global.fetch,\n\t\trefreshToken: string,\n\t): Promise<ArmorTokenExchange> => {\n\t\tconst body = new URLSearchParams({\n\t\t\tgrant_type: \"refresh_token\",\n\t\t\tclient_id: config.oauth.clientId,\n\t\t\tclient_secret: config.oauth.clientSecret,\n\t\t\trefresh_token: refreshToken,\n\t\t});\n\n\t\tif (config.oauth.scope) {\n\t\t\tbody.set(\"scope\", config.oauth.scope);\n\t\t}\n\n\t\tconst response = await fetch(refreshEndpoint, {\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\tAccept: \"application/json\",\n\t\t\t},\n\t\t\tbody: body.toString(),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst error = await response.text();\n\t\t\tthrow new ArmorRefreshError(`Could not refresh token: ${error}`);\n\t\t}\n\n\t\tconst json: ArmorTokenExchange = await response.json();\n\n\t\treturn {\n\t\t\t...json,\n\t\t\trefresh_token: json.refresh_token ?? refreshToken,\n\t\t};\n\t};\n\n\tconst postRefresh = async (\n\t\texchange: ArmorTokenExchange,\n\t): Promise<ArmorTokens> => {\n\t\tconst jwks = createRemoteJWKSet(jwksUrl);\n\n\t\tconst [idToken, accessToken] = await Promise.all([\n\t\t\tjwtVerifyIdToken(config, jwks, exchange.id_token),\n\t\t\tjwtVerifyAccessToken(config, jwks, exchange.access_token),\n\t\t]);\n\n\t\treturn exchangeToTokens(exchange, idToken as ArmorIdToken, accessToken);\n\t};\n\n\treturn {\n\t\trefresh,\n\t\tasync ensureValidToken<T>(\n\t\t\tfetch: typeof global.fetch,\n\t\t\ttokens: ArmorTokens,\n\t\t\tfn: (tokens: ArmorTokens) => T | Promise<T>,\n\t\t): Promise<T> {\n\t\t\tlet validTokens = tokens;\n\n\t\t\tif (shouldRefresh(tokens)) {\n\t\t\t\tthrowIfUndefined(tokens.exchange.refresh_token);\n\t\t\t\tconst newTokens = await refresh(fetch, tokens.exchange.refresh_token);\n\t\t\t\tvalidTokens = await postRefresh(newTokens);\n\t\t\t}\n\n\t\t\treturn fn(validTokens);\n\t\t},\n\t\tasync handler(\n\t\t\tevent: RequestEvent,\n\t\t\ttokens: ArmorTokens,\n\t\t): Promise<ArmorTokens> {\n\t\t\tconst refreshToken = tokens.exchange?.refresh_token;\n\n\t\t\tif (!refreshToken) {\n\t\t\t\tthrow new ArmorRefreshError(\"Could not find refresh token\");\n\t\t\t}\n\n\t\t\tconst exchange = await refresh(event.fetch, refreshToken);\n\n\t\t\treturn postRefresh(exchange);\n\t\t},\n\t};\n}\n","import { error, json } from \"@sveltejs/kit\";\nimport type { ArmorConfig } from \"../contracts\";\nimport type { RouteFactory } from \"./routes\";\nimport { armorCreateRefresh } from \"../utils/refresh\";\nimport { ARMOR_REFRESH } from \"../browser\";\nimport { ArmorRefreshError } from \"../errors\";\n\nexport const ROUTE_PATH_REFRESH = ARMOR_REFRESH;\n\nexport const routeRefreshFactory: RouteFactory = (config: ArmorConfig) => {\n\tconst refresh = armorCreateRefresh(config);\n\n\treturn {\n\t\tpath: ROUTE_PATH_REFRESH,\n\t\tmethod: \"POST\",\n\t\tasync handle({ event }) {\n\t\t\ttry {\n\t\t\t\tconst tokens = await config.session.getTokens(event);\n\n\t\t\t\tif (!tokens) {\n\t\t\t\t\treturn error(401, \"Unauthorized\");\n\t\t\t\t}\n\n\t\t\t\tconst { idToken, accessToken } = await refresh.handler(event, tokens);\n\n\t\t\t\treturn json({ idToken, accessToken });\n\t\t\t} catch (ex) {\n\t\t\t\tif (ex instanceof ArmorRefreshError) {\n\t\t\t\t\treturn error(401, \"Unauthorized\");\n\t\t\t\t}\n\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t},\n\t};\n};\n","import type { Handle } from \"@sveltejs/kit\";\nimport type { ArmorConfig } from \"../contracts\";\nimport { routeLoginFactory } from \"./login\";\nimport { routeLogoutFactory } from \"./logout\";\nimport { routeRedirectLogoutFactory } from \"./redirect-logout\";\nimport { routeRedirectLoginFactory } from \"./redirect-login\";\nimport { routeRefreshFactory } from \"./refresh\";\n\nexport interface Route {\n\treadonly path: string;\n\treadonly handle: Handle;\n\treadonly method: \"GET\" | \"POST\";\n}\n\nexport type RouteFactory = (config: ArmorConfig) => Route | undefined;\n\nconst routeFactories = Object.freeze([\n\trouteLoginFactory,\n\trouteLogoutFactory,\n\trouteRedirectLoginFactory,\n\trouteRedirectLogoutFactory,\n\trouteRefreshFactory,\n]);\n\nexport function routeCreate(config: ArmorConfig): Map<string, Route> {\n\t// @ts-expect-error Incorrect typing error.\n\treturn new Map(\n\t\trouteFactories\n\t\t\t.map((routeFactory) => routeFactory(config))\n\t\t\t.filter((route) => Boolean(route))\n\t\t\t// @ts-expect-error Incorrect typing error.\n\t\t\t.map((route) => [route.path, route]),\n\t);\n}\n","import { RequestEvent } from \"@sveltejs/kit\";\nimport {\n\tCOOKIE_TOKENS,\n\tcookieDelete,\n\tcookieGet,\n\tcookieSet,\n} from \"../utils/cookie\";\nimport { ArmorConfig, ArmorTokens } from \"../contracts\";\nimport { ArmorAuthMissingError } from \"../errors\";\n\nfunction cookieSessionGetTokens({\n\tcookies,\n}: RequestEvent): ArmorTokens | undefined {\n\treturn cookies.get(COOKIE_TOKENS) as ArmorTokens | undefined;\n}\n\nexport function cookieSessionLogin(\n\t{ cookies }: RequestEvent,\n\ttokens: ArmorTokens,\n): void {\n\tcookieSet(cookies, COOKIE_TOKENS, tokens);\n}\n\nfunction cookieSessionLogout({ cookies }: RequestEvent): void {\n\tcookieDelete(cookies, COOKIE_TOKENS);\n}\n\nexport function armorCookieSessionGet({ cookies }: RequestEvent): ArmorTokens {\n\tconst tokens = cookieGet<ArmorTokens>(cookies, COOKIE_TOKENS);\n\n\tif (!tokens) {\n\t\tthrow new ArmorAuthMissingError();\n\t}\n\n\treturn tokens;\n}\n\nexport const armorCookieSession: ArmorConfig[\"session\"] = {\n\tgetTokens: cookieSessionGetTokens,\n\tlogin: cookieSessionLogin,\n\tlogout: cookieSessionLogout,\n};\n","import { redirect, type Handle } from \"@sveltejs/kit\";\nimport { ROUTE_PATH_LOGIN } from \"./routes/login\";\nimport type { ArmorConfig, ArmorOpenIdConfig, ArmorTokens } from \"./contracts\";\nimport { routeCreate } from \"./routes/routes\";\nimport { ArmorOpenIdConfigError, ArmorRefreshError } from \"./errors\";\nimport { shouldRefresh } from \"./utils/utils\";\nimport { armorCreateRefresh } from \"./utils/refresh\";\n\nexport type { ArmorConfig, ArmorTokens };\nexport { armorCookieSession, armorCookieSessionGet } from \"./session/cookie\";\nexport { armorCreateRefresh } from \"./utils/refresh\";\n\nexport function armor(config: ArmorConfig): Handle {\n\tconst routeByPath = routeCreate(config);\n\tconst refresh = armorCreateRefresh(config);\n\n\treturn async ({ event, resolve }) => {\n\t\tconst route = routeByPath.get(event.url.pathname);\n\n\t\tif (route && route.method === event.request.method) {\n\t\t\treturn route.handle({ event, resolve });\n\t\t}\n\n\t\tconst tokens = await config.session.getTokens(event);\n\n\t\tif (!tokens) {\n\t\t\tthrow redirect(302, ROUTE_PATH_LOGIN);\n\t\t}\n\n\t\ttry {\n\t\t\tif (shouldRefresh(tokens)) {\n\t\t\t\tconsole.log(\"Refreshing token...\");\n\t\t\t\tawait refresh.handler(event, tokens);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (error instanceof ArmorRefreshError) {\n\t\t\t\tconsole.error(\"Could not refresh token. Redirect user to login...\");\n\t\t\t\tthrow redirect(302, ROUTE_PATH_LOGIN);\n\t\t\t}\n\n\t\t\tthrow error;\n\t\t}\n\n\t\treturn resolve(event);\n\t};\n}\n\n/**\n * Some IdP's expose a /.well-known/openid-configuration that specifies how to configure.\n * Use that to create your config.\n * @param config\n * @param fetch\n */\nexport async function armorConfigFromOpenId(\n\tconfig: ArmorOpenIdConfig,\n\tfetch?: typeof global.fetch,\n): Promise<ArmorConfig> {\n\tconst fetchToUse = fetch ?? global.fetch;\n\n\tconst response = await fetchToUse(config.oauth.openIdConfigEndpoint, {\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t});\n\n\tif (!response.ok) {\n\t\tconst text = await response.text();\n\t\tthrow new ArmorOpenIdConfigError(text);\n\t}\n\n\tconst body = await response.json();\n\n\treturn {\n\t\t...config,\n\t\toauth: {\n\t\t\t...config.oauth,\n\t\t\ttokenEndpoint: body.token_endpoint,\n\t\t\tauthorizeEndpoint: body.authorization_endpoint,\n\t\t\tissuer: body.issuer,\n\t\t\tjwksEndpoint: body.jwks_uri,\n\t\t\tlogoutEndpoint: body.end_session_endpoint ?? undefined,\n\t\t\trefreshEndpoint: body.token_endpoint,\n\t\t},\n\t};\n}\n"],"names":["urlConcat","origin","path","strTrimEnd","strTrimStart","join","isTokenExchange","value","obj","access_token","token_type","expires_in","id_token","undefined","refresh_token","scope","MINUTES_MS","shouldRefresh","tokens","accessExpiry","accessToken","exp","Infinity","expiry","Math","min","idToken","Date","now","createExpiresAt","seconds","setSeconds","getSeconds","exchangeToTokens","exchange","expiresAt","jwtIsCompactJwt","token","parts","trim","split","length","every","p","jwtVerifyIdToken","config","jwks","payload","jwtVerifyToken","issuer","oauth","audience","clientId","throwIfUndefined","jwtVerifyAccessToken","opts","isInvalidCompactJwt","error","Boolean","message","test","jwtVerify","COOKIE_TOKENS","COOKIE_STATE","cookieDeleteOptions","Object","freeze","cookieSetOptions","httpOnly","secure","sameSite","maxAge","cookieSet","cookies","key","set","JSON","stringify","cookieGetAndDelete","cookieGet","delete","get","parse","cookieDelete","ArmorError","Error","ArmorOpenIdConfigError","ArmorInvalidStateError","ArmorAuthMissingError","ArmorRefreshError","eventStateValidOrThrow","event","_event$url$searchPara","state","url","searchParams","stateCookie","ROUTE_PATH_REDIRECT_LOGIN","routeRedirectLoginFactory","_config$oauth$jwksEnd","_config$oauth$tokenEn","_config$oauth$scope","jwksUrl","URL","jwksEndpoint","baseUrl","tokenUrl","tokenEndpoint","exchangeCodeForToken","fetch","code","params","grant_type","client_id","client_secret","clientSecret","redirect_uri","response","method","headers","Accept","body","URLSearchParams","toString","ok","text","json","handle","_event$url$searchPara3","_event$url$searchPara2","error_description","errorLoginRedirectPath","Response","trimEnd","errorParams","queryParamsCreate","redirect","createRemoteJWKSet","Promise","all","session","login","ARMOR_REFRESH","ARMOR_LOGIN","ROUTE_PATH_LOGIN","routeLoginFactory","_config$oauth$authori","authorizeEndpoint","randomUUID","response_type","ROUTE_PATH_REDIRECT_LOGOUT","routeRedirectLogoutFactory","logoutEndpoint","logout","ROUTE_PATH_LOGOUT","routeLogoutFactory","_config$oauth$logoutR","returnTo","logoutReturnToParam","armorCreateRefresh","_config$oauth$refresh","refreshEndpoint","refresh","refreshToken","_json$refresh_token","postRefresh","ensureValidToken","fn","validTokens","newTokens","handler","_tokens$exchange","ROUTE_PATH_REFRESH","routeRefreshFactory","getTokens","ex","routeFactories","routeCreate","Map","map","routeFactory","filter","route","cookieSessionGetTokens","cookieSessionLogin","cookieSessionLogout","armorCookieSessionGet","armorCookieSession","armor","routeByPath","resolve","pathname","request","console","log","armorConfigFromOpenId","_body$end_session_end","fetchToUse","global","openIdConfigEndpoint","token_endpoint","authorization_endpoint","jwks_uri","end_session_endpoint"],"mappings":"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"}
|
package/dist/utils/refresh.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
import { ArmorConfig, ArmorTokens } from "../contracts";
|
|
1
|
+
import { ArmorConfig, ArmorTokenExchange, ArmorTokens } from "../contracts";
|
|
2
2
|
import { RequestEvent } from "@sveltejs/kit";
|
|
3
|
-
export declare function armorCreateRefresh(config: ArmorConfig):
|
|
3
|
+
export declare function armorCreateRefresh(config: ArmorConfig): {
|
|
4
|
+
refresh: (fetch: typeof global.fetch, refreshToken: string) => Promise<ArmorTokenExchange>;
|
|
5
|
+
ensureValidToken<T>(fetch: typeof global.fetch, tokens: ArmorTokens, fn: (tokens: ArmorTokens) => T | Promise<T>): Promise<T>;
|
|
6
|
+
handler(event: RequestEvent, tokens: ArmorTokens): Promise<ArmorTokens>;
|
|
7
|
+
};
|
package/dist/utils/utils.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { ArmorTokenExchange, ArmorTokens } from "../contracts";
|
|
1
|
+
import type { ArmorAccessToken, ArmorIdToken, ArmorTokenExchange, ArmorTokens } from "../contracts";
|
|
2
2
|
export declare function urlConcat(origin: string, path: string): string;
|
|
3
3
|
export declare function isTokenExchange(value: unknown): value is ArmorTokenExchange;
|
|
4
|
-
export declare function shouldRefresh(tokens: ArmorTokens): boolean;
|
|
4
|
+
export declare function shouldRefresh(tokens: Pick<ArmorTokens, "idToken" | "accessToken">): boolean;
|
|
5
5
|
export declare function createExpiresAt(seconds: number): Date;
|
|
6
|
+
export declare function exchangeToTokens(exchange: ArmorTokenExchange, idToken: ArmorIdToken, accessToken?: ArmorAccessToken): ArmorTokens;
|
package/package.json
CHANGED
package/src/browser/index.ts
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
|
+
import { ArmorTokens } from "../contracts";
|
|
1
2
|
import { ArmorRefreshError } from "../errors";
|
|
2
|
-
|
|
3
|
-
export interface ArmorBrowserRefresh {
|
|
4
|
-
readonly idToken: string;
|
|
5
|
-
readonly accessToken: string;
|
|
6
|
-
readonly expiresAt: Date;
|
|
7
|
-
}
|
|
3
|
+
import { shouldRefresh } from "../utils/utils";
|
|
8
4
|
|
|
9
5
|
export const ARMOR_REFRESH = "/_armor/refresh";
|
|
10
6
|
export const ARMOR_LOGIN = "/_armor/login";
|
|
11
7
|
|
|
12
|
-
|
|
8
|
+
type ArmorBrowserTokens = Pick<ArmorTokens, "idToken" | "accessToken">;
|
|
9
|
+
|
|
10
|
+
export async function armorBrowserRefresh(): Promise<ArmorBrowserTokens> {
|
|
13
11
|
const response = await fetch(ARMOR_REFRESH, {
|
|
14
12
|
method: "POST",
|
|
15
13
|
headers: {
|
|
@@ -30,3 +28,14 @@ export async function armorBrowserRefresh(): Promise<ArmorBrowserRefresh> {
|
|
|
30
28
|
|
|
31
29
|
return response.json();
|
|
32
30
|
}
|
|
31
|
+
|
|
32
|
+
export async function armorBrowserEnsureValidTokens<T>(
|
|
33
|
+
tokens: ArmorBrowserTokens,
|
|
34
|
+
fn: (tokens: ArmorBrowserTokens) => T | Promise<T>,
|
|
35
|
+
): Promise<T> {
|
|
36
|
+
const validTokens = shouldRefresh(tokens)
|
|
37
|
+
? await armorBrowserRefresh()
|
|
38
|
+
: tokens;
|
|
39
|
+
|
|
40
|
+
return fn(validTokens);
|
|
41
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -30,7 +30,7 @@ export function armor(config: ArmorConfig): Handle {
|
|
|
30
30
|
try {
|
|
31
31
|
if (shouldRefresh(tokens)) {
|
|
32
32
|
console.log("Refreshing token...");
|
|
33
|
-
await refresh(event, tokens);
|
|
33
|
+
await refresh.handler(event, tokens);
|
|
34
34
|
}
|
|
35
35
|
} catch (error) {
|
|
36
36
|
if (error instanceof ArmorRefreshError) {
|
|
@@ -7,7 +7,7 @@ import type {
|
|
|
7
7
|
import { queryParamsCreate, throwIfUndefined } from "@nekm/core";
|
|
8
8
|
import { createRemoteJWKSet } from "jose";
|
|
9
9
|
import type { RouteFactory } from "./routes";
|
|
10
|
-
import { urlConcat, isTokenExchange,
|
|
10
|
+
import { urlConcat, isTokenExchange, exchangeToTokens } from "../utils/utils";
|
|
11
11
|
import { jwtVerifyAccessToken, jwtVerifyIdToken } from "../utils/jwt";
|
|
12
12
|
import { eventStateValidOrThrow } from "../utils/event";
|
|
13
13
|
|
|
@@ -111,14 +111,10 @@ export const routeRedirectLoginFactory: RouteFactory = (
|
|
|
111
111
|
jwtVerifyAccessToken(config, jwks, exchange.access_token),
|
|
112
112
|
]);
|
|
113
113
|
|
|
114
|
-
await config.session.login(
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
// access token. Most cases, this doesn't matter.
|
|
119
|
-
accessToken: accessToken ?? exchange.access_token,
|
|
120
|
-
expiresAt: createExpiresAt(exchange.expires_in),
|
|
121
|
-
});
|
|
114
|
+
await config.session.login(
|
|
115
|
+
event,
|
|
116
|
+
exchangeToTokens(exchange, idToken as ArmorIdToken, accessToken),
|
|
117
|
+
);
|
|
122
118
|
|
|
123
119
|
throw redirect(302, "/");
|
|
124
120
|
},
|
package/src/routes/refresh.ts
CHANGED
|
@@ -21,12 +21,9 @@ export const routeRefreshFactory: RouteFactory = (config: ArmorConfig) => {
|
|
|
21
21
|
return error(401, "Unauthorized");
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
const { idToken,
|
|
25
|
-
event,
|
|
26
|
-
tokens,
|
|
27
|
-
);
|
|
24
|
+
const { idToken, accessToken } = await refresh.handler(event, tokens);
|
|
28
25
|
|
|
29
|
-
return json({ idToken,
|
|
26
|
+
return json({ idToken, accessToken });
|
|
30
27
|
} catch (ex) {
|
|
31
28
|
if (ex instanceof ArmorRefreshError) {
|
|
32
29
|
return error(401, "Unauthorized");
|
package/src/utils/refresh.ts
CHANGED
|
@@ -6,9 +6,10 @@ import {
|
|
|
6
6
|
ArmorTokens,
|
|
7
7
|
} from "../contracts";
|
|
8
8
|
import { ArmorRefreshError } from "../errors";
|
|
9
|
-
import {
|
|
9
|
+
import { exchangeToTokens, shouldRefresh, urlConcat } from "./utils";
|
|
10
10
|
import { jwtVerifyAccessToken, jwtVerifyIdToken } from "./jwt";
|
|
11
11
|
import { RequestEvent } from "@sveltejs/kit";
|
|
12
|
+
import { throwIfUndefined } from "@nekm/core";
|
|
12
13
|
|
|
13
14
|
export function armorCreateRefresh(config: ArmorConfig) {
|
|
14
15
|
const refreshEndpoint =
|
|
@@ -56,32 +57,49 @@ export function armorCreateRefresh(config: ArmorConfig) {
|
|
|
56
57
|
};
|
|
57
58
|
};
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
tokens: ArmorTokens,
|
|
60
|
+
const postRefresh = async (
|
|
61
|
+
exchange: ArmorTokenExchange,
|
|
62
62
|
): Promise<ArmorTokens> => {
|
|
63
|
-
const refreshToken = tokens.exchange?.refresh_token;
|
|
64
|
-
|
|
65
|
-
if (!refreshToken) {
|
|
66
|
-
throw new ArmorRefreshError("Could not find refresh token");
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const newExchange = await refresh(event.fetch, refreshToken);
|
|
70
|
-
|
|
71
63
|
const jwks = createRemoteJWKSet(jwksUrl);
|
|
72
64
|
|
|
73
65
|
const [idToken, accessToken] = await Promise.all([
|
|
74
|
-
jwtVerifyIdToken(config, jwks,
|
|
75
|
-
jwtVerifyAccessToken(config, jwks,
|
|
66
|
+
jwtVerifyIdToken(config, jwks, exchange.id_token),
|
|
67
|
+
jwtVerifyAccessToken(config, jwks, exchange.access_token),
|
|
76
68
|
]);
|
|
77
69
|
|
|
78
|
-
return
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
70
|
+
return exchangeToTokens(exchange, idToken as ArmorIdToken, accessToken);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
refresh,
|
|
75
|
+
async ensureValidToken<T>(
|
|
76
|
+
fetch: typeof global.fetch,
|
|
77
|
+
tokens: ArmorTokens,
|
|
78
|
+
fn: (tokens: ArmorTokens) => T | Promise<T>,
|
|
79
|
+
): Promise<T> {
|
|
80
|
+
let validTokens = tokens;
|
|
81
|
+
|
|
82
|
+
if (shouldRefresh(tokens)) {
|
|
83
|
+
throwIfUndefined(tokens.exchange.refresh_token);
|
|
84
|
+
const newTokens = await refresh(fetch, tokens.exchange.refresh_token);
|
|
85
|
+
validTokens = await postRefresh(newTokens);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return fn(validTokens);
|
|
89
|
+
},
|
|
90
|
+
async handler(
|
|
91
|
+
event: RequestEvent,
|
|
92
|
+
tokens: ArmorTokens,
|
|
93
|
+
): Promise<ArmorTokens> {
|
|
94
|
+
const refreshToken = tokens.exchange?.refresh_token;
|
|
95
|
+
|
|
96
|
+
if (!refreshToken) {
|
|
97
|
+
throw new ArmorRefreshError("Could not find refresh token");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const exchange = await refresh(event.fetch, refreshToken);
|
|
101
|
+
|
|
102
|
+
return postRefresh(exchange);
|
|
103
|
+
},
|
|
86
104
|
};
|
|
87
105
|
}
|
package/src/utils/utils.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { strTrimEnd, strTrimStart } from "@nekm/core";
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
ArmorAccessToken,
|
|
4
|
+
ArmorIdToken,
|
|
5
|
+
ArmorTokenExchange,
|
|
6
|
+
ArmorTokens,
|
|
7
|
+
} from "../contracts";
|
|
3
8
|
|
|
4
9
|
export function urlConcat(origin: string, path: string): string {
|
|
5
10
|
return [strTrimEnd(origin, "/"), strTrimStart(path, "/")].join("/");
|
|
@@ -24,8 +29,16 @@ export function isTokenExchange(value: unknown): value is ArmorTokenExchange {
|
|
|
24
29
|
|
|
25
30
|
const MINUTES_MS = 60 * 1000;
|
|
26
31
|
|
|
27
|
-
export function shouldRefresh(
|
|
28
|
-
|
|
32
|
+
export function shouldRefresh(
|
|
33
|
+
tokens: Pick<ArmorTokens, "idToken" | "accessToken">,
|
|
34
|
+
): boolean {
|
|
35
|
+
const accessExpiry =
|
|
36
|
+
typeof tokens.accessToken !== "string" && tokens.accessToken.exp
|
|
37
|
+
? tokens.accessToken.exp
|
|
38
|
+
: Infinity;
|
|
39
|
+
const expiry = Math.min(tokens.idToken.exp, accessExpiry);
|
|
40
|
+
|
|
41
|
+
return expiry < Date.now() + 5 * MINUTES_MS;
|
|
29
42
|
}
|
|
30
43
|
|
|
31
44
|
export function createExpiresAt(seconds: number): Date {
|
|
@@ -33,3 +46,18 @@ export function createExpiresAt(seconds: number): Date {
|
|
|
33
46
|
now.setSeconds(now.getSeconds() + seconds);
|
|
34
47
|
return now;
|
|
35
48
|
}
|
|
49
|
+
|
|
50
|
+
export function exchangeToTokens(
|
|
51
|
+
exchange: ArmorTokenExchange,
|
|
52
|
+
idToken: ArmorIdToken,
|
|
53
|
+
accessToken?: ArmorAccessToken,
|
|
54
|
+
): ArmorTokens {
|
|
55
|
+
return {
|
|
56
|
+
exchange,
|
|
57
|
+
idToken: idToken as ArmorIdToken,
|
|
58
|
+
// Generally, IdP's require an audience to get a JWT
|
|
59
|
+
// access token. Most cases, this doesn't matter.
|
|
60
|
+
accessToken: accessToken ?? exchange.access_token,
|
|
61
|
+
expiresAt: createExpiresAt(exchange.expires_in),
|
|
62
|
+
};
|
|
63
|
+
}
|