Suggestions

close search

Add Messaging, Voice, and Authentication to your apps with Vonage Communications APIs

Visit the Vonage API Developer Portal
Developer Documentation moved on August 7, 2026. Future updates are available only at → https://developer.vonage.com/en/opentok/overview

End-to-End Encryption

Important notes:

  • In OpenTok.js 2.27.0+, end-to-end encryption will not work when connecting to clients using an earlier version of OpenTok.js. When you upgrade your app to use OpenTok.js 2.27.0+, make sure all clients are using OpenTok.js 2.27.0+ if the app uses end-to-end encryption.
  • End-to-end encryption supported on WebKit-based browsers, for example Safari on macOS/iOS and Chrome on iOS, is only available from version OpenTok.js 2.30.0 onwards.

This topic includes details on using end-to-end encryption in the OpenTok.js Vonage Video client SDK:

For an overview of end-to-end encryption, see this topic.

Note about Content Security Policies (CSP)

If the script-src directive is set, make sure 'wasm-unsafe-eval' is specified. Otherwise WebAssembly, required for end-to-end encryption, is blocked from loading and executing on the page.

Initializing a session with a secret

End-to-end encrypted sessions are created using server APIs (see Enabling encryption using the REST API). To have a web client join an end-to-end encrypted session, specify an encryption secret when calling the OT.initSession() method:

const session = OT.initSession(
  'api-key',
  'session-id',
  {
    encryptionSecret: 'initialEncryptionSecret'
  }
});

A valid secret is a string between 8 and 256 characters. The secret can later be changed with the Session.setEncryptionSecret() method (see Changing the secret, below).

Checking whether the browser supports end-to-end encryption

Use the OT.hasEndToEndEncryptionSupport() method to check if the client's browser supports end-to-end encryption:

if (OT.hasEndToEndEncryptionSupport()) {
  // Proceed with connecting to the session
}
else {
  // Notify the user that they cannot join the session
}

Changing the secret

You can change the secret using the Session.setEncryptionSecret() method after the session has connected:

await session.setEncryptionSecret('newEncryptionSecret');

Events and errors

Events and errors are essential to managing the behavior of user-driven encryption behavior. End-to-end encryption uses the shared secret model: everyone in the session is expected to use the same secret to encrypt their media and decrypt everyone else's.

A Subscriber object dispatches an encryptionSecretMismatch event when the subscriber is unable to decode a stream's media. It is important to communicate to the user that media is not being received due to an encryption mismatch and not due to a connection failure or audio/video bug:

subscriber.on('encryptionSecretMismatch', () => {
  // Activate a UI element communicating that there's been an encryption secret mismatch.
});

Also, it is important to communicate to users that encryption has been successfully enabled. A Subscriber object dispatches an encryptionSecretMatch event when the subscriber is able to decode the stream's media after a previous mismatch.

subscriber.on('encryptionSecretMatch', () => {
  // Activate a UI element communicating that the media is being properly decrypted.
});

The Session.connect() callback is invoked with an error if the client tries to connect to an end-to-end encrypted session that was initialized with an invalid encryption secret. A valid secret is a string between 8 and 256 characters. For the best user experience, the application should catch an invalid user supplied secret before calling theOT.initSession() method. In the following example, a session is initialized with an empty (and thus invalid) secret, which causes an error when attempting to connect:

const session = OT.initSession(
 'api-key',
 'e2ee-session-id',
 {
   encryptionSecret: '',
 }
)

session.connect('token', (error) => {
  if (error && error.name === 'OT_INVALID_ENCRYPTION_SECRET') {
    /*
    The application should communicate that the secret was invalid.
    */
  }
});

The Session.connect() callback is invoked with an error if a user attempts to connect to an end-to-end encrypted session in a browser that does not support end-to-end encryption.

const session = OT.initSession(
 'api-key',
 'e2ee-session-id',
 {
   encryptionSecret: 'validEncryptionSecret',
 }
)

session.connect('token', (error) => {
  if (error && error.name === 'OT_UNSUPPORTED_BROWSER') {
    /*
    The error will have the message 'Tried to connect an e2ee session but the browser does not support e2ee'
    The application should communicate that the browser does not support encryption.
    */
  }
});

If a user tries to publish in an end-to-end encrypted session without having specified an encryption secret, the Session.publish() callback is invoked with an error. For the best user experience, the application should validate a user-supplied secret before calling the session.publish() method:

session.publish(publisher, (error) => {
  if (error && error.name === 'OT_STREAM_CREATE_FAILED') {
    /*
    The error will have the message 'Tried to publish to an e2ee session but encryption secret was not set'
    The application should communicate that the secret was not set.
    */
  }
});

If a user tries to subscribe in an end-to-end encrypted session without having specified an encryption secret, the Session.subscribe() callback is invoked with an error. For the best user experience, the application should validate a user-supplied secret before calling the Session.subscribe() method:

subscriber = session.subscribe(stream, target, opts, (error) => {
  if (error && error.name === 'OT_UNABLE_TO_SUBSCRIBE') {
    /*
    The error will have the message 'Tried to subscribe to an e2ee stream but encryption secret was not set'
    The application should communicate that the secret was not set.
    */
  }
});