backend: Implement participant token handling with cookie management and validation middleware

This commit is contained in:
juancarmore 2025-03-13 15:04:59 +01:00
parent e9882c19dc
commit a692f8e37f
4 changed files with 41 additions and 6 deletions

View File

@ -5,6 +5,8 @@ import { TokenOptions } from '@typings-ce';
import { OpenViduMeetError } from '../models/index.js';
import { ParticipantService } from '../services/participant.service.js';
import { RoomService } from '../services/room.service.js';
import { MEET_PARTICIPANT_TOKEN_EXPIRATION, PARTICIPANT_TOKEN_COOKIE_NAME } from '../environment.js';
import { getCookieOptions } from '../utils/cookie-utils.js';
export const generateParticipantToken = async (req: Request, res: Response) => {
const logger = container.get(LoggerService);
@ -28,8 +30,7 @@ export const generateParticipantToken = async (req: Request, res: Response) => {
const secretRole = await roomService.getRoomSecretRole(roomName, secret);
const token = await participantService.generateParticipantToken(secretRole, tokenOptions);
// TODO: Set the participant token in a cookie
// res.cookie('ovParticipantToken', token, { httpOnly: true, expires: tokenTtl });
res.cookie(PARTICIPANT_TOKEN_COOKIE_NAME, token, getCookieOptions('/', MEET_PARTICIPANT_TOKEN_EXPIRATION));
logger.verbose(`Participant token generated for room ${roomName}`);
return res.status(200).json({ token });

View File

@ -19,10 +19,11 @@ export const {
MEET_SECRET = 'user',
MEET_ADMIN_USER = 'admin',
MEET_ADMIN_SECRET = 'admin',
MEET_PARTICIPANT_TOKEN_EXPIRATION = '6h',
MEET_ACCESS_TOKEN_EXPIRATION = '2h',
MEET_REFRESH_TOKEN_EXPIRATION = '1d',
MEET_PREFERENCES_STORAGE_MODE = 's3',
MEET_WEBHOOK_ENABLED = 'true',
MEET_WEBHOOK_ENABLED = 'false',
MEET_WEBHOOK_URL = 'http://localhost:5080/webhook',
MEET_LOG_LEVEL = 'info',
@ -60,6 +61,7 @@ export const {
export const MEET_API_BASE_PATH = '/meet/api';
export const MEET_API_BASE_PATH_V1 = MEET_API_BASE_PATH + '/v1';
export const PARTICIPANT_TOKEN_COOKIE_NAME = 'OvMeetParticipantToken';
export const ACCESS_TOKEN_COOKIE_NAME = 'OvMeetAccessToken';
export const REFRESH_TOKEN_COOKIE_NAME = 'OvMeetRefreshToken';

View File

@ -8,7 +8,8 @@ import {
MEET_API_KEY,
MEET_PRIVATE_ACCESS,
MEET_SECRET,
MEET_USER
MEET_USER,
PARTICIPANT_TOKEN_COOKIE_NAME
} from '../environment.js';
import { container } from '../config/dependency-injector.config.js';
@ -35,6 +36,31 @@ export const withAdminValidToken = async (req: Request, res: Response, next: Nex
next();
};
export const withParticipantValidToken = async (req: Request, res: Response, next: NextFunction) => {
const token = req.cookies[PARTICIPANT_TOKEN_COOKIE_NAME];
if (!token) {
return res.status(401).json({ message: 'Unauthorized' });
}
const tokenService = container.get(TokenService);
try {
const payload = await tokenService.verifyToken(token);
// Parse metadata if it exists and add payload to request body for further processing
if (payload.metadata) {
payload.metadata = JSON.parse(payload.metadata);
}
req.body.payload = payload;
} catch (error) {
return res.status(401).json({ message: 'Invalid token' });
}
next();
};
export const withValidApiKey = async (req: Request, res: Response, next: NextFunction) => {
const apiKey = req.headers['x-api-key'];

View File

@ -14,7 +14,13 @@ import {
SendDataOptions,
StreamOutput
} from 'livekit-server-sdk';
import { LIVEKIT_API_KEY, LIVEKIT_API_SECRET, LIVEKIT_URL, LIVEKIT_URL_PRIVATE } from '../environment.js';
import {
LIVEKIT_API_KEY,
LIVEKIT_API_SECRET,
LIVEKIT_URL,
LIVEKIT_URL_PRIVATE,
MEET_PARTICIPANT_TOKEN_EXPIRATION
} from '../environment.js';
import { LoggerService } from './logger.service.js';
import {
errorLivekitIsNotAvailable,
@ -142,7 +148,7 @@ export class LiveKitService {
const at = new AccessToken(LIVEKIT_API_KEY, LIVEKIT_API_SECRET, {
identity: participantName,
name: participantName,
ttl: '24h',
ttl: MEET_PARTICIPANT_TOKEN_EXPIRATION,
metadata: JSON.stringify({
livekitUrl: LIVEKIT_URL,
role,