05aad75272
Multi-tenant AI help desk SaaS for the firearms industry. Full monorepo: API (Express/Prisma), Worker (BullMQ), Frontend (React/Vite/Tailwind). PostgreSQL 16 + pgvector, Redis 7, JWT auth, RLS tenant isolation. Dark Armory theme with tactical branding throughout. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
37 lines
1.1 KiB
TypeScript
37 lines
1.1 KiB
TypeScript
import jwt from 'jsonwebtoken';
|
|
|
|
const ACCESS_SECRET = process.env.JWT_ACCESS_SECRET || 'dev-access-secret-minimum-32-characters';
|
|
const REFRESH_SECRET = process.env.JWT_REFRESH_SECRET || 'dev-refresh-secret-minimum-32-characters';
|
|
const ACCESS_EXPIRY = process.env.JWT_ACCESS_EXPIRY || '15m';
|
|
const REFRESH_EXPIRY = process.env.JWT_REFRESH_EXPIRY || '7d';
|
|
|
|
export interface TokenPayload {
|
|
userId: string;
|
|
tenantId: string;
|
|
email: string;
|
|
role: string;
|
|
}
|
|
|
|
export function signAccessToken(payload: TokenPayload): string {
|
|
return jwt.sign(payload, ACCESS_SECRET, { expiresIn: ACCESS_EXPIRY });
|
|
}
|
|
|
|
export function signRefreshToken(payload: TokenPayload): string {
|
|
return jwt.sign(payload, REFRESH_SECRET, { expiresIn: REFRESH_EXPIRY });
|
|
}
|
|
|
|
export function verifyAccessToken(token: string): TokenPayload {
|
|
return jwt.verify(token, ACCESS_SECRET) as TokenPayload;
|
|
}
|
|
|
|
export function verifyRefreshToken(token: string): TokenPayload {
|
|
return jwt.verify(token, REFRESH_SECRET) as TokenPayload;
|
|
}
|
|
|
|
export function generateTokenPair(payload: TokenPayload) {
|
|
return {
|
|
accessToken: signAccessToken(payload),
|
|
refreshToken: signRefreshToken(payload),
|
|
};
|
|
}
|