nimeet Docs
中文

Channel Encryption

Media encryption vs transport encryption, configuration, key rotation and supported modes.

Version v1.1.0 · Updated 2026-10-26 · revision 1

"Encryption" has two completely different layers in real-time audio and video, and mixing them up is the easiest way to get it wrong. This page separates them first, then explains what we do at each layer.

The two layers

LayerWhat it protectsWho is responsibleOur status
Transport encryptionThe link between the client and the media serverThe platform (DTLS-SRTP + HTTPS/WSS)✅ On by default, no configuration needed
Media encryption (E2EE)End to end, so even the media server cannot decryptApplication-layer key agreement + SDK encryption➖ Not implemented, explicitly NOT_SUPPORTED

Transport encryption (default)

  • Signalling uses https:// / wss://; media uses SRTP (DTLS-SRTP by default in LiveKit).
  • You do not need to call any API; your reverse proxy must allow WebSocket upgrades, otherwise connections degrade into failures (see the troubleshooting manual).
  • AgoraRTC.on('security-policy-violation') fires when browser security policy (mixed content, permissions policy and so on) blocks something, which makes diagnosis easier.

Media encryption: in the interface definition, explicitly rejected at runtime

The Agora Web SDK surface includes a setEncryptionConfig:

javascript
client.setEncryptionConfig('aes-256-gcm2', secret, salt, true);

Our implementation branches on it explicitly:

javascript
// Explicitly declaring "no encryption" is allowed, which makes it easy to move Agora code over unchanged (secret must not be an empty string, otherwise INVALID_PARAMS is reported first)
client.setEncryptionConfig('none', 'no-secret-used');

// Any encryption mode other than 'none' throws instead of silently succeeding
try {
  client.setEncryptionConfig('aes-256-gcm2', 'a-32-byte-secret-material........', undefined, true);
} catch (error) {
  // error.code === 'NOT_SUPPORTED'
  // error.message === 'end-to-end encryption is not supported by the ni-meet media adapter yet'
}

Behaviour details (taken from the implementation, not inferred):

InputBehaviour
encryptionMode empty / secret not a string or emptyThrows INVALID_PARAMS
encryptionMode === 'none'Accepted, configuration recorded, no encryption applied
Any other mode (aes-128-xts, aes-256-gcm2, sm4-128-ecb…)Throws NOT_SUPPORTED (AgoraRTCError.code === 'NOT_SUPPORTED')

The EncryptionMode type in the interface definition is complete (9 values), because the public surface must match Agora exactly; whether a mode is supported is a runtime capability, not a type.

Viable paths when you need E2EE

  1. Application-layer encryption (recommended for most teams): media stays plain SRTP, but sensitive content (whiteboard data, files) is encrypted end to end at the application layer and sent over the data channel.
  2. Build your own E2EE media layer: plug an engine that supports SFrame/Insertable Streams into the media adapter layer, and wire setEncryptionConfig to it while keeping the SDK interface definition. This is engineering investment, not a configuration option.
  3. Choose another solution: if compliance hard-requires media-level E2EE and in-house development is not acceptable, this requirement does not match the current capabilities of this project and should be surfaced early rather than worked around.

Key management (applies to every path)

  • Keys never go into client bundles or front-end environment variables;
  • Use a separate key per session and discard it when the session ends;
  • Key rotation does not affect issued tokens (tokens govern authorization, keys govern encryption; the two are independent);
  • Audit logs record only "enabled or not" and "rotation time", never the key itself.

Common misconceptions

MisconceptionFact
"The token contains salt, so it is encrypted"salt is only a randomiser for the token signature and has nothing to do with media encryption
"setEncryptionConfig returned void, so it worked"We throw on unsupported modes; not throwing only means 'none' or that parameter validation passed
"HTTPS is end-to-end encryption"HTTPS only reaches the server; beyond the server the traffic is plaintext or another TLS segment
"Turning encryption on makes it laggier"E2EE has overhead, but we do not provide it, so this trade-off does not exist here

Generated by the documentation build pipeline · 2026-10-31 01:24:02 UTC · Documentation center v1.1.0.

Content follows the public API definitions.

ni-meet is a self-hosted RTC PaaS with a LiveKit-based media plane (Apache-2.0) and an Agora-compatible API.