You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#生成LiveKit JWT Token无效问题求助

解决C#生成LiveKit JWT Token时video claim为字符串的问题

问题根源

LiveKit的JWT要求video、audio这类权限Claim是JSON对象类型(例如{"canPublish": true, "canSubscribe": true}),但C#默认的Claim构造器仅支持字符串值,直接将对象序列化后存入Claim会导致JWT解码后该字段为字符串而非对象,最终Token无效。

解决方案:直接构造JWT Payload而非依赖默认Claim系统

绕过默认Claim只能存字符串的限制,手动构造包含对象类型字段的Payload,让JWT库直接将其序列化为JSON对象。

方法1:使用Dictionary<string, object>构造Payload

这种方式最直接,JWT库会自动将对象类型的值序列化为JSON对象:

using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Text;
using Microsoft.IdentityModel.Tokens;

public string GenerateLiveKitToken(string apiKey, string apiSecret, string roomName, string identity)
{
    var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(apiSecret));
    var signingCreds = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

    // 构造包含对象类型权限的Payload
    var payload = new Dictionary<string, object>
    {
        ["iss"] = apiKey,
        ["sub"] = identity,
        ["room"] = roomName,
        ["exp"] = DateTimeOffset.UtcNow.AddHours(1).ToUnixTimeSeconds(),
        // video字段直接用匿名对象,JWT库会序列化为JSON对象
        ["video"] = new
        {
            canPublish = true,
            canSubscribe = true,
            canPublishSources = new[] { "camera", "screen" }
        },
        ["audio"] = new
        {
            canPublish = true,
            canSubscribe = true
        }
    };

    var token = new JwtSecurityToken(
        issuer: apiKey,
        payload: payload,
        expires: DateTime.UtcNow.AddHours(1),
        signingCredentials: signingCreds
    );

    return new JwtSecurityTokenHandler().WriteToken(token);
}

方法2:使用JObject构造Payload(适合复杂场景)

如果需要更灵活的JSON结构(比如动态添加字段),可以用Newtonsoft.Json的JObject:

using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Text;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json.Linq;

public string GenerateLiveKitToken(string apiKey, string apiSecret, string roomName, string identity)
{
    var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(apiSecret));
    var signingCreds = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

    var payload = new JObject
    {
        ["iss"] = apiKey,
        ["sub"] = identity,
        ["room"] = roomName,
        ["exp"] = DateTimeOffset.UtcNow.AddHours(1).ToUnixTimeSeconds(),
        ["video"] = new JObject
        {
            ["canPublish"] = true,
            ["canSubscribe"] = true,
            ["canPublishSources"] = new JArray("camera", "screen")
        }
    };

    // 将JObject转换为Claim列表,指定JSON类型
    var claims = new List<System.Security.Claims.Claim>();
    foreach (var prop in payload.Properties())
    {
        var valueType = prop.Value.Type switch
        {
            JTokenType.Object or JTokenType.Array => "json",
            _ => null
        };
        claims.Add(new System.Security.Claims.Claim(prop.Name, prop.Value.ToString(), valueType));
    }

    var token = new JwtSecurityToken(
        issuer: apiKey,
        claims: claims,
        expires: DateTime.UtcNow.AddHours(1),
        signingCredentials: signingCreds
    );

    return new JwtSecurityTokenHandler().WriteToken(token);
}

关键注意事项

  • 确保安装了必要的NuGet包:System.IdentityModel.Tokens.Jwt(必选)、Newtonsoft.Json(方法2需要)
  • 权限字段的命名和大小写要严格符合LiveKit的要求,比如canPublish、canSubscribe不能写错
  • 过期时间exp必须是Unix时间戳(或用DateTime类型让库自动转换),否则Token会被判定为无效

内容的提问来源于stack exchange,提问作者Diego Satizabal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 10:01:01