MCPcopy Create free account
hub / github.com/ACM-VIT/conclave / verifyTranscriptToken

Function verifyTranscriptToken

apps/web/transcript-worker/src/auth.ts:82–128  ·  view source on GitHub ↗
(
  token: string,
  secret: string,
)

Source from the content-addressed store, hash-verified

80};
81
82export const verifyTranscriptToken = async (
83 token: string,
84 secret: string,
85): Promise<TranscriptTokenPayload | null> => {
86 const parts = token.split(".");
87 if (parts.length !== 3) return null;
88 const [header, payload, signature] = parts;
89 if (!header || !payload || !signature) return null;
90
91 const encoder = new TextEncoder();
92 const key = await crypto.subtle.importKey(
93 "raw",
94 encoder.encode(secret),
95 { name: "HMAC", hash: "SHA-256" },
96 false,
97 ["verify"],
98 );
99 const valid = await crypto.subtle.verify(
100 "HMAC",
101 key,
102 base64UrlToBytes(signature),
103 encoder.encode(`${header}.${payload}`),
104 );
105 if (!valid) return null;
106
107 const parsed = safeJsonParse(
108 new TextDecoder().decode(base64UrlToBytes(payload)),
109 );
110 if (!parsed || typeof parsed !== "object") return null;
111 const data = parsed as TranscriptTokenPayload;
112 if (data.aud !== "conclave-transcript-worker") return null;
113 if (!data.exp || data.exp * 1000 < Date.now()) return null;
114 if (!data.userId || !data.roomId) return null;
115 return {
116 aud: data.aud,
117 exp: data.exp,
118 sub: data.sub,
119 userId: data.userId,
120 displayName: data.displayName,
121 roomId: data.roomId,
122 clientId: data.clientId,
123 channelId: data.channelId,
124 isAdmin: data.isAdmin,
125 isHost: data.isHost,
126 capabilities: data.capabilities,
127 };
128};
129
130export const verifyTranscriptRoomToken = async (
131 token: string,

Callers 2

Calls 4

safeJsonParseFunction · 0.90
base64UrlToBytesFunction · 0.85
decodeMethod · 0.80
nowMethod · 0.80

Tested by

no test coverage detected