backend: add 'iat' timestamp to token metadata and update related validation logic
This commit is contained in:
parent
73e7a1ece7
commit
3df0c54004
@ -17,13 +17,13 @@ import {
|
||||
} from '../models/error.model.js';
|
||||
import { TokenType } from '../models/token-metadata.model.js';
|
||||
import { RoomMemberRepository } from '../repositories/room-member.repository.js';
|
||||
import { RoomRepository } from '../repositories/room.repository.js';
|
||||
import { ApiKeyService } from '../services/api-key.service.js';
|
||||
import { LoggerService } from '../services/logger.service.js';
|
||||
import { RequestSessionService } from '../services/request-session.service.js';
|
||||
import { TokenService } from '../services/token.service.js';
|
||||
import { UserService } from '../services/user.service.js';
|
||||
import { getAccessToken, getRoomMemberToken } from '../utils/token.utils.js';
|
||||
import { RoomRepository } from '../repositories/room.repository.js';
|
||||
|
||||
/**
|
||||
* Interface for authentication validators.
|
||||
@ -192,7 +192,7 @@ export const roomMemberTokenValidator: AuthValidator = {
|
||||
try {
|
||||
// Verify the token and extract the room member token metadata
|
||||
const tokenService = container.get(TokenService);
|
||||
const { iat, metadata: tokenMetadata } = await tokenService.verifyToken(token);
|
||||
const { metadata: tokenMetadata } = await tokenService.verifyToken(token);
|
||||
|
||||
if (!tokenMetadata) {
|
||||
throw new Error('Missing required token claims');
|
||||
@ -200,10 +200,10 @@ export const roomMemberTokenValidator: AuthValidator = {
|
||||
|
||||
// Validate the room member token metadata
|
||||
const parsedMetadata = tokenService.parseRoomMemberTokenMetadata(tokenMetadata);
|
||||
const { roomId, memberId } = parsedMetadata;
|
||||
const { iat, roomId, memberId } = parsedMetadata;
|
||||
|
||||
// If the token has a memberId, validate that permissions haven't been updated after token issuance
|
||||
if (memberId && iat) {
|
||||
if (memberId) {
|
||||
const roomMemberRepository = container.get(RoomMemberRepository);
|
||||
const roomMember = await roomMemberRepository.findByRoomAndMemberId(roomId, memberId);
|
||||
|
||||
@ -211,7 +211,7 @@ export const roomMemberTokenValidator: AuthValidator = {
|
||||
if (!roomMember || iat < roomMember.permissionsUpdatedAt) {
|
||||
throw new Error('Token has outdated permissions');
|
||||
}
|
||||
} else if (!memberId && iat) {
|
||||
} else {
|
||||
// If the token has no memberId (anonymous access), validate that room roles/anonymous haven't been updated
|
||||
const roomRepository = container.get(RoomRepository);
|
||||
const room = await roomRepository.findByRoomId(roomId, 'rolesUpdatedAt');
|
||||
|
||||
@ -2,6 +2,9 @@
|
||||
* Metadata associated with access, refresh, and temporary tokens.
|
||||
*/
|
||||
export interface TokenMetadata {
|
||||
/** Token issued at timestamp (milliseconds since epoch) */
|
||||
iat: number;
|
||||
/** Type of the token */
|
||||
tokenType: TokenType;
|
||||
}
|
||||
|
||||
|
||||
@ -7,5 +7,6 @@ export const LoginReqSchema = z.object({
|
||||
});
|
||||
|
||||
export const TokenMetadataSchema: z.ZodType<TokenMetadata> = z.object({
|
||||
iat: z.number(),
|
||||
tokenType: z.nativeEnum(TokenType)
|
||||
});
|
||||
|
||||
@ -126,6 +126,7 @@ export const RoomMemberTokenOptionsSchema: z.ZodType<MeetRoomMemberTokenOptions>
|
||||
);
|
||||
|
||||
export const RoomMemberTokenMetadataSchema: z.ZodType<MeetRoomMemberTokenMetadata> = z.object({
|
||||
iat: z.number(),
|
||||
livekitUrl: z.string().url('LiveKit URL must be a valid URL'),
|
||||
roomId: z.string(),
|
||||
memberId: z.string().optional(),
|
||||
|
||||
@ -612,6 +612,7 @@ export class RoomMemberService {
|
||||
|
||||
const livekitPermissions = this.getLiveKitPermissions(roomId, effectivePermissions);
|
||||
const tokenMetadata: MeetRoomMemberTokenMetadata = {
|
||||
iat: Date.now(),
|
||||
livekitUrl: MEET_ENV.LIVEKIT_URL,
|
||||
roomId,
|
||||
memberId,
|
||||
@ -644,6 +645,7 @@ export class RoomMemberService {
|
||||
);
|
||||
|
||||
const tokenMetadata: MeetRoomMemberTokenMetadata = {
|
||||
iat: Date.now(),
|
||||
livekitUrl: MEET_ENV.LIVEKIT_URL,
|
||||
roomId,
|
||||
memberId,
|
||||
|
||||
@ -16,6 +16,7 @@ export class TokenService {
|
||||
|
||||
async generateAccessToken(user: MeetUser, isTemporary = false): Promise<string> {
|
||||
const tokenMetadata: TokenMetadata = {
|
||||
iat: Date.now(),
|
||||
tokenType: isTemporary ? TokenType.TEMPORARY : TokenType.ACCESS
|
||||
};
|
||||
const tokenOptions: AccessTokenOptions = {
|
||||
@ -41,6 +42,7 @@ export class TokenService {
|
||||
|
||||
async generateRefreshToken(user: MeetUser): Promise<string> {
|
||||
const tokenMetadata: TokenMetadata = {
|
||||
iat: Date.now(),
|
||||
tokenType: TokenType.REFRESH
|
||||
};
|
||||
const tokenOptions: AccessTokenOptions = {
|
||||
|
||||
@ -72,6 +72,8 @@ export interface MeetRoomMemberTokenOptions {
|
||||
* Contains information about the room and member permissions.
|
||||
*/
|
||||
export interface MeetRoomMemberTokenMetadata {
|
||||
/** Token issued at timestamp (milliseconds since epoch) */
|
||||
iat: number;
|
||||
livekitUrl: string;
|
||||
roomId: string;
|
||||
memberId?: string;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user