You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

49 lines
1.3 KiB

import { SignJWT, jwtVerify, decodeJwt } from "jose";
import type { JWTPayload } from "jose";
let rawSecret = process.env.JWT_SECRET;
if (!rawSecret) {
if (process.env.NODE_ENV === "production") {
throw new Error("JWT_SECRET environment variable is required in production");
}
rawSecret = "dev-secret-change-in-production";
}
const JWT_SECRET = new TextEncoder().encode(rawSecret);
const ACCESS_TOKEN_EXPIRY = "15m";
export interface AccessTokenPayload extends JWTPayload {
userId: number;
sessionId: string;
role: string;
}
export async function signAccessToken(payload: {
userId: number;
sessionId: string;
role: string;
}): Promise<string> {
return new SignJWT(payload as Record<string, unknown>)
.setProtectedHeader({ alg: "HS256" })
.setIssuedAt()
.setExpirationTime(ACCESS_TOKEN_EXPIRY)
.sign(JWT_SECRET);
}
export async function verifyAccessToken(
token: string
): Promise<AccessTokenPayload | null> {
try {
const { payload } = await jwtVerify(token, JWT_SECRET);
return payload as AccessTokenPayload;
} catch {
return null;
}
}
export function decodeAccessTokenNoVerify(token: string): AccessTokenPayload | null {
try {
return decodeJwt(token) as AccessTokenPayload;
} catch {
return null;
}
}