UNPKG

wcz-layout

Version:

75 lines (74 loc) 3.62 kB
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