UNPKG

wcz-layout

Version:

1 lines 8.27 kB
{"version":3,"file":"authMiddleware-DkRImzMr.mjs","names":["createMiddleware","axios","AxiosError","https","serverEnv","scopes","definedScopes","getAppToken","getTokenOnBehalfOf","getAccessToken","ApiMiddlewareOptions","baseURL","scopeKey","httpsAgent","Agent","rejectUnauthorized","apiMiddleware","server","next","request","resolvedBaseURL","process","env","Error","authHeader","headers","get","accessToken","startsWith","substring","length","api","create","Authorization","context","error","response","data","message","createMiddleware","jose","permissions","serverEnv","getSessionUser","buildUser","hasPermission","TokenPayload","User","resolveUser","request","Request","Promise","authHeader","headers","get","startsWith","payload","verifyToken","substring","length","error","Response","json","message","Error","status","requiredAuthenticationMiddleware","server","user","next","context","publicAuthenticationMiddleware","authenticationMiddleware","options","optional","authorizationMiddleware","permissionKey","middleware","name","token","jwtVerify","getJWKS","issuer","ENTRA_TENANT_ID","audience","ENTRA_CLIENT_ID","jwksCache","ReturnType","createRemoteJWKSet","URL"],"sources":["../src/middleware/apiMiddleware.ts","../src/middleware/authMiddleware.ts"],"sourcesContent":["import { createMiddleware } from \"@tanstack/react-start\";\nimport axios, { AxiosError } from \"axios\";\nimport https from \"node:https\";\nimport type { serverEnv } from \"virtual:wcz-layout\";\nimport { scopes as definedScopes } from \"virtual:wcz-layout\";\nimport { getAppToken, getTokenOnBehalfOf } from \"~/lib/auth/msalServer\";\nimport { getAccessToken } from \"~/lib/auth/user\";\n\ninterface ApiMiddlewareOptions {\n baseURL: keyof typeof serverEnv & `${string}BASE_URL${string}`;\n scopeKey: keyof typeof definedScopes;\n}\n\nconst httpsAgent = new https.Agent({\n rejectUnauthorized: false,\n});\n\nexport const apiMiddleware = ({ baseURL, scopeKey }: ApiMiddlewareOptions) =>\n createMiddleware().server(async ({ next, request }) => {\n const resolvedBaseURL = process.env[baseURL];\n if (!resolvedBaseURL) throw new Error(`\"${baseURL}\" env variable is not set.`);\n\n const authHeader = request.headers.get(\"Authorization\");\n let accessToken: string;\n if (authHeader?.startsWith(\"Bearer \")) {\n accessToken = await getTokenOnBehalfOf(authHeader.substring(\"Bearer \".length), scopeKey);\n } else {\n try {\n accessToken = await getAccessToken(scopeKey);\n } catch {\n accessToken = await getAppToken(scopeKey);\n }\n }\n\n const api = axios.create({\n baseURL: resolvedBaseURL,\n httpsAgent,\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n\n try {\n return await next({ context: { api } });\n } catch (error) {\n if (error instanceof AxiosError)\n throw new Error(error.response?.data?.message ?? error.message);\n throw error;\n }\n });\n","import { createMiddleware } from \"@tanstack/react-start\";\nimport * as jose from \"jose\";\nimport type { permissions } from \"virtual:wcz-layout\";\nimport { serverEnv } from \"~/env\";\nimport { getSessionUser } from \"~/lib/auth/user\";\nimport { buildUser, hasPermission } from \"~/lib/utils\";\nimport type { TokenPayload } from \"~/models/TokenPayload\";\nimport type { User } from \"~/models/User\";\n\nasync function resolveUser(request: Request): Promise<User | null> {\n const authHeader = request.headers.get(\"Authorization\");\n\n if (authHeader?.startsWith(\"Bearer \")) {\n let payload: TokenPayload;\n try {\n payload = await verifyToken(authHeader.substring(\"Bearer \".length));\n } catch (error) {\n throw Response.json(\n { message: error instanceof Error ? error.message : \"Unauthorized: Invalid access token\" },\n { status: 401 },\n );\n }\n return buildUser(payload);\n }\n\n return getSessionUser();\n}\n\nconst requiredAuthenticationMiddleware = createMiddleware().server<{ user: User }>(\n async ({ next, request }) => {\n const user = await resolveUser(request);\n\n if (!user)\n throw Response.json({ message: \"Unauthorized: User not signed in\" }, { status: 401 });\n\n return next({ context: { user } });\n },\n);\n\nconst publicAuthenticationMiddleware = createMiddleware().server<{ user: User | null }>(\n async ({ next, request }) => {\n const user = await resolveUser(request);\n return next({ context: { user } });\n },\n);\n\nexport function authenticationMiddleware(options?: {\n optional?: false;\n}): typeof requiredAuthenticationMiddleware;\n\nexport function authenticationMiddleware(options: {\n optional: true;\n}): typeof publicAuthenticationMiddleware;\n\nexport function authenticationMiddleware(options: {\n optional: boolean;\n}): typeof requiredAuthenticationMiddleware | typeof publicAuthenticationMiddleware;\n\nexport function authenticationMiddleware(options?: { optional?: boolean }) {\n return options?.optional ? publicAuthenticationMiddleware : requiredAuthenticationMiddleware;\n}\n\nexport const authorizationMiddleware = (permissionKey: keyof typeof permissions) =>\n createMiddleware()\n .middleware([authenticationMiddleware()])\n .server(async ({ next, context }) => {\n if (hasPermission(context.user, permissionKey)) return next();\n throw Response.json(\n {\n message: `Forbidden: User ${context.user.name} is not authorized to access this resource`,\n },\n { status: 403 },\n );\n });\n\nasync function verifyToken(token: string): Promise<TokenPayload> {\n const { payload } = await jose.jwtVerify(token, getJWKS(), {\n issuer: `https://login.microsoftonline.com/${serverEnv.ENTRA_TENANT_ID}/v2.0`,\n audience: serverEnv.ENTRA_CLIENT_ID,\n });\n return payload as unknown as TokenPayload;\n}\n\nlet jwksCache: ReturnType<typeof jose.createRemoteJWKSet> | null = null;\n\nfunction getJWKS() {\n jwksCache ??= jose.createRemoteJWKSet(\n new URL(`https://login.microsoftonline.com/${serverEnv.ENTRA_TENANT_ID}/discovery/v2.0/keys`),\n );\n return jwksCache;\n}\n"],"mappings":"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"}