hrms-api-eva/src/utils/auth.ts
DESKTOP-2S5P7D1\Windows 10 925c5d1ab2 first
2024-12-04 17:25:34 +07:00

76 lines
2.5 KiB
TypeScript

import * as express from "express";
import { createDecoder, createVerifier } from "fast-jwt";
import HttpError from "../interfaces/http-error";
import HttpStatusCode from "../interfaces/http-status";
if (!process.env.PUBLIC_KEY && !process.env.REALM_URL) {
throw new Error("Requires PUBLIC_KEY or REALM_URL");
}
if (process.env.PUBLIC_KEY && process.env.REALM_URL && !process.env.PREFERRED_AUTH) {
throw new Error(
"PREFERRED_AUTH must be specified when both REALM_URL and PUBLIC_KEY are provided.",
);
}
const jwtVerify = createVerifier({
key: async () => {
return `-----BEGIN PUBLIC KEY-----\n${process.env.PUBLIC_KEY}\n-----END PUBLIC KEY-----`;
},
});
const jwtDecode = createDecoder();
export async function expressAuthentication(
request: express.Request,
securityName: string,
scopes?: string[],
) {
if (process.env.AUTH_BYPASS) return { preferred_username: "bypassed" };
if (securityName !== "bearerAuth") throw new Error("Unknown authentication method.");
const token = request.headers["authorization"]?.includes("Bearer ")
? request.headers["authorization"].split(" ")[1]
: request.headers["authorization"];
if (!token) throw new HttpError(HttpStatusCode.UNAUTHORIZED, "กรุณาเข้าสู่ระบบก่อนใช้งาน!");
let payload: Record<string, any> = {};
switch (process.env.PREFERRED_AUTH) {
case "online":
payload = await verifyOnline(token);
break;
case "offline":
payload = await verifyOffline(token);
break;
default:
if (process.env.REALM_URL) payload = await verifyOnline(token);
if (process.env.PUBLIC_KEY) payload = await verifyOffline(token);
break;
}
if (scopes && scopes.length > 0 && scopes.every((v) => !payload.role.includes(v))) {
throw new HttpError(HttpStatusCode.FORBIDDEN, "You are not allowed to perform this action.");
}
return payload;
}
async function verifyOffline(token: string) {
const payload = await jwtVerify(token).catch((_) => null);
if (!payload) throw new HttpError(HttpStatusCode.UNAUTHORIZED, "Invalid token provided.");
return payload;
}
async function verifyOnline(token: string) {
const res = await fetch(`${process.env.REALM_URL}/protocol/openid-connect/userinfo`, {
headers: { authorization: `Bearer ${token}` },
}).catch((e) => console.error(e));
if (!res) throw new Error("Cannot connect to auth service.");
if (!res.ok) throw new HttpError(HttpStatusCode.UNAUTHORIZED, "Invalid token provided.");
return await jwtDecode(token);
}