50 lines
1.4 KiB
TypeScript
50 lines
1.4 KiB
TypeScript
export const getRawJsonWebToken = (): string | null => {
|
|
return localStorage.getItem("token");
|
|
};
|
|
|
|
export const getJsonWebToken = (): JwtPayload | null => {
|
|
const rawToken = getRawJsonWebToken();
|
|
return rawToken ? parseJwt(rawToken) : null;
|
|
};
|
|
|
|
export const parseJwt = (token: string): JwtPayload | null => {
|
|
try {
|
|
const base64Url = token.split(".")[1];
|
|
const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
|
|
const jsonPayload = decodeURIComponent(
|
|
atob(base64)
|
|
.split("")
|
|
.map((c) => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2))
|
|
.join("")
|
|
);
|
|
const jwtPayload = JSON.parse(jsonPayload);
|
|
return isJwtPayloadValid(jwtPayload) ? jwtPayload : null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
export const isJwtPayloadValid = (jwtPayload: JwtPayload): boolean => {
|
|
return (
|
|
claims.every((claim) => Object.keys(jwtPayload).includes(claim)) &&
|
|
userRoles.includes(jwtPayload.role) &&
|
|
typeof jwtPayload.person_row_id === "number" &&
|
|
typeof jwtPayload.exp === "number" &&
|
|
typeof jwtPayload.iat === "number"
|
|
);
|
|
};
|
|
|
|
const claims = ["role", "person_row_id", "exp", "iat", "aud", "iss"];
|
|
const userRoles = ["candymat_editor", "candymat_candidate", "candymat_person"];
|
|
|
|
interface JwtPayload {
|
|
role: UserRole;
|
|
person_row_id: number;
|
|
exp: number;
|
|
iat: number;
|
|
aud: "postgraphile";
|
|
iss: "postgraphile";
|
|
}
|
|
|
|
type UserRole = "candymat_editor" | "candymat_candidate" | "candymat_person";
|