wcz-layout
Version:
75 lines (74 loc) • 3.62 kB
JavaScript
import { i as buildUser, m as serverEnv, u as getAccessToken } from "./utils-CqQKSaSs.js";
import { z } from "zod";
import { createMiddleware } from "@tanstack/react-start";
import * as jose from "jose";
//#region src/middleware/authMiddleware.ts
const requiredAuthenticationMiddleware = createMiddleware().server(async ({ next, request }) => {
const accessToken = request.headers.get("Authorization");
if (!accessToken?.startsWith("Bearer")) throw Response.json({ message: "Unauthorized: Invalid Authorization header" }, { status: 401 });
let tokenPayload;
try {
tokenPayload = await verifyToken(accessToken.substring(7));
} catch (error) {
throw Response.json({ message: error instanceof Error ? error.message : "Unauthorized: Invalid access token" }, { status: 401 });
}
return next({ context: { user: buildUser(tokenPayload) } });
});
const publicAuthenticationMiddleware = createMiddleware().server(async ({ next, request }) => {
const accessToken = request.headers.get("Authorization");
if (!accessToken?.startsWith("Bearer")) return next({ context: { user: null } });
let tokenPayload;
try {
tokenPayload = await verifyToken(accessToken.substring(7));
} catch (error) {
throw Response.json({ message: error instanceof Error ? error.message : "Unauthorized: Invalid access token" }, { status: 401 });
}
return next({ context: { user: buildUser(tokenPayload) } });
});
function authenticationMiddleware(options) {
return options?.optional ? publicAuthenticationMiddleware : requiredAuthenticationMiddleware;
}
const authorizationMiddleware = (permissionKey) => createMiddleware().middleware([authenticationMiddleware()]).server(async ({ next, context }) => {
if (context.user.hasPermission(permissionKey)) return next();
throw Response.json({ message: `Forbidden: User ${context.user.name} is not authorized to access this resource` }, { status: 403 });
});
const serverFnAccessTokenMiddleware = (scopeKey) => createMiddleware({ type: "function" }).client(async ({ next }) => {
try {
return next({ headers: { Authorization: `Bearer ${await getAccessToken(scopeKey)}` } });
} catch {
return next();
}
});
async function verifyToken(token) {
const { payload } = await jose.jwtVerify(token, getJWKS(), {
issuer: `https://login.microsoftonline.com/${serverEnv.ENTRA_TENANT_ID}/v2.0`,
audience: serverEnv.ENTRA_CLIENT_ID
});
return payload;
}
let jwksCache = null;
function getJWKS() {
jwksCache ??= jose.createRemoteJWKSet(new URL(`https://login.microsoftonline.com/${serverEnv.ENTRA_TENANT_ID}/discovery/v2.0/keys`));
return jwksCache;
}
//#endregion
//#region src/middleware/validationMiddleware.ts
const validationMiddleware = (schema) => createMiddleware().server(async ({ next, request }) => {
const json = await request.json();
const result = schema.safeParse(json);
if (!result.success) {
const { fieldErrors } = z.flattenError(result.error);
const firstFieldName = Object.keys(fieldErrors)[0];
const firstErrorMessage = fieldErrors[firstFieldName]?.[0];
if (firstFieldName && firstErrorMessage) {
const name = firstFieldName.charAt(0).toUpperCase() + firstFieldName.slice(1);
const message = firstErrorMessage.replace(/^Invalid input:\s*/i, "").toLowerCase();
return Response.json({ message: `${name} - ${message}` }, { status: 400 });
}
return Response.json({ message: "Validation failed" }, { status: 400 });
}
return await next({ context: { data: result.data } });
});
//#endregion
export { authenticationMiddleware, authorizationMiddleware, serverFnAccessTokenMiddleware, validationMiddleware };
//# sourceMappingURL=middleware.js.map