End-to-End Encryption API
Use the End-to-End Encryption API to encrypt media being sent through a media server from your application.
Important: 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.
Overview
End-to-end encryption (or E2EE) allows application developers to encrypt media in routed sessions from client to client. For relayed sessions, media is already encrypted client-to-client, through WebRTC protocols. This feature adds an encryption layer by encrypting the media payload at the client so that it will remain encrypted through the Media Router that routes media to other clients (in routed sessions). You enable end-to-end encryption when you create a session.
End-to-end encryption is supported in web apps on Chromium-based (Chrome, Opera, Samsung Internet, Edge and Android WebView) and WebKit-based browsers, for example Safari on macOS/iOS, Chrome on iOS and WebView on iOS. End-to-end encryption is not supported in web apps on Firefox.
WebKit-based browser support is only available from version OpenTok.js 2.30.0 onwards.
End-to-end encryption is supported in each of the native client SDKs (for Android, iOS, Windows, Linux, and macOS).
You set the encryption secret in a web application using OpenTok.js. You must set encryption secrets in the web client when you initialize a session, and you can change encryption secrets on the fly once the session has connected. The encryption secret is a non-empty string. All users must use the same secret to receive intelligible media. The encryption secret is key material for generating a cryptographic key that is used to encrypt and decrypt media. Specifically, the encryption secret generates an AES-256 encryption key using an AES-CTR algorithm with a 256-bit key.
Please note that the Media Router does not have access to unencrypted media when using end-to-end encryption.
So, features that require media decoding --- such as archiving, live streaming broadcasts, experience composer, audio connector, and SIP interconnect --- are unsupported in end-to-end encrypted sessions. .
End-to-End encryption per codec support across endpoints
| Codec/End-point | Chrome | Android Chrome | iOS Chrome | Firefox | Safari | Edge | iOS SDK | Android SDK | Windows SDK | macOS SDK | Linux SDK |
|---|---|---|---|---|---|---|---|---|---|---|---|
| VP8 | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| H.264 | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| VP9 | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Adding end-to-end encryption for your account
End-to-end encryption is available as an add-on feature. You can enable it on your Video account page.
Enabling encryption using the REST API
You enable end-to-end encryption when you create a session using the REST API. Set the e2ee property to true.
See session creation.
Note: Before enabling end-to-end encryption for a session, you must enable it for your Video account.
The following Node.js example creates an end-to-end encryption enabled session:
const Vonage = require('@vonage/server-sdk');
const vonage = new Vonage({
applicationId: APP_ID,
privateKey: PRIVATE_KEY_PATH
});
try {
const session = await vonage.video.createSession({
mediaMode: "routed",
e2ee: true, // This will enable end-to-end encryption
});
} catch(error) {
console.error("Error creating session: ", error);
}
Implementations
Setting the encryption secret
End-to-end encrypted sessions are created using server APIs (see Enabling encryption using the REST API). To have a React Native client join an end-to-end encrypted session, set the encryptionSecret prop of the OTSession component:
<OTSession
applicationId="api-key"
sessionId="session-id"
token="token"
encryptionSecret="initial-encryption-secret"
>
<OTPublisher />
<OTSubscriber />
</OTSession>
A valid secret is a string between 8 and 256 characters.
You can change the secret by setting the encryptionSecret prop to a property of the React state and changing its value:
<OTSession
applicationId="api-key"
sessionId="session-id"
token="token"
encryptionSecret={this.state.encryptionSecret}>
>
<OTPublisher />
<OTSubscriber />
</OTSession>
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.
The OTSubscriber error() event handler callback is invoked when the subscriber is unable to decode a stream's media due to a mismatched (or unset) encryption secret:
<OTSubscriber
eventHandlers={{
error: event => {
// Show UI notification.
},
}}
>
The OTSession error() event handler callback is invoked if the client tries to connect to an end-to-end encrypted session that was initialized with an invalid encryption secret (or without specifying an 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 setting the OTSession encryptionSecret prop. In the following example, a session is initialized with an empty (and thus invalid) secret, which causes an error when attempting to connect:
<OTSession
applicationId="api-key"
sessionId="session-id"
token="token"
encryptionSecret=""
eventHanders={{
error: event => {
// An error event is dispatched if you set an invalid encryption secret
}
}}
>
<OTPublisher />
<OTSubscriber />
</OTSession>
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 support 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.
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
}
End-to-end encryption is not currently supported in Firefox.
Changing the secret
You can change the secret using the Session.setEncryptionSecret() method after the session has connected:
await session.setEncryptionSecret('newEncryptionSecret');
If the session does not have end-to-end encryption enabled, setting a secret results in an OT_ENCRYPTION_NOT_ENABLED error. See Setting a secret in a session without end-to-end encryption.
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.
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 the OT.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.
*/
}
});
Setting a secret in a session without end-to-end encryption
Note: This behavior is available starting with version 2.36.0 of the SDK.
If a session was not created with end-to-end encryption enabled, setting an encryption secret for it results in an OT_ENCRYPTION_NOT_ENABLED error. Where the error surfaces depends on when the secret is set relative to connecting, publishing, and subscribing.
Note: The scenarios in this section assume the client's browser supports end-to-end encryption. In a browser that does not support it, using end-to-end encryption can result in an OT_UNSUPPORTED_BROWSER error instead. See Checking whether the browser supports end-to-end encryption and Events and errors.
Setting the secret before connecting
If the secret is set before connecting — either with the encryptionSecret option of OT.initSession() or by calling Session.setEncryptionSecret() — the session connects successfully. The error is returned in the Session.publish() and Session.subscribe() callbacks:
// Option 1: set the secret when initializing the session
const session = OT.initSession('api-key', 'non-e2ee-session-id', {
encryptionSecret: 'encryptionSecret',
});
// Option 2: set the secret before connecting
// await session.setEncryptionSecret('encryptionSecret');
session.connect('token', (error) => {
if (error) {
return;
}
session.publish(publisher, (error) => {
if (error && error.name === 'OT_ENCRYPTION_NOT_ENABLED') {
/*
The application should communicate that end-to-end encryption
is not enabled for this session.
*/
}
});
session.subscribe(stream, target, opts, (error) => {
if (error && error.name === 'OT_ENCRYPTION_NOT_ENABLED') {
// Same handling as for the publisher.
}
});
});
Setting the secret after connecting
If Session.setEncryptionSecret() is called after the session has connected, the method rejects with the error. Any subsequent call to Session.publish() or Session.subscribe() also returns the error in its callback:
session.connect('token', async (error) => {
if (error) {
return;
}
try {
await session.setEncryptionSecret('encryptionSecret');
} catch (error) {
if (error.name === 'OT_ENCRYPTION_NOT_ENABLED') {
/*
The application should communicate that end-to-end encryption
is not enabled for this session.
*/
}
}
});
Setting the secret while publishing or subscribing
If Session.setEncryptionSecret() is called while the client is already publishing or subscribing, the method rejects with the error, and every active Publisher and Subscriber object dispatches an encryptionNotEnabled event. The SDK then stops those publishers and subscribers automatically, so you do not need to call Session.unpublish() or Session.unsubscribe():
publisher.on('encryptionNotEnabled', (event) => {
// The publisher is stopped by the SDK. No need to call session.unpublish().
});
subscriber.on('encryptionNotEnabled', (event) => {
// The subscriber is stopped by the SDK. No need to call session.unsubscribe().
});
try {
await session.setEncryptionSecret('encryptionSecret');
} catch (error) {
if (error.name === 'OT_ENCRYPTION_NOT_ENABLED') {
// An encryptionNotEnabled event is also dispatched on every
// active publisher and subscriber (handled above).
}
}
Recovering from the error
The session remains valid after any of these errors. To publish or subscribe again, clear the secret by calling Session.setEncryptionSecret() with null. The same Publisher object can then be passed to Session.publish() again:
await session.setEncryptionSecret(null);
session.publish(publisher, (error) => {
// Publishing proceeds without end-to-end encryption.
});
Setting the encryption secret
End-to-end encrypted sessions are created using server APIs (see Enabling encryption using the REST API).
Before the client publishes or subscribes, call the Session.setEncryptionSecret() method:
session.setEncryptionSecret("encryption-secret");
session.connect(TOKEN);
A valid secret is a string between 8 and 256 characters. You can change the secret by calling the Session.setEncryptionSecret() function again.
Setting an invalid secret will result in an InvalidEncryptionSecret error.
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.
If a client tries to connect to an end-to-end encrypted session without setting an encryption secret, the SessionListener.onError() event handler is called with an error code set to ErrorCode.EncryptionSecretMissing:
// Implementation of SessionListener.onError():
@Override
public void onError(Session session, OpentokError opentokError) {
if (opentokError.getErrorCode() == ErrorCode.EncryptionSecretMissing) {
// Notify the user that they cannot join the session
}
}
session.connect(token);
If a user tries to publish in an end-to-end encrypted session without having specified an encryption secret, calling the Session.publish() method results in the PublisherListener.onError() event handler being called with an error that has the code set to ErrorCode.EncryptionSecretMissing. For the best user experience, the application should validate a user-supplied secret before calling the Session.publish() method:
// Implementation of PublisherListener.onError():
@Override
public void onError(PublisherKit publisher, OpentokError opentokError) {
if (opentokError.getErrorCode() == ErrorCode.EncryptionInternalError) {
// The application should communicate that the secret was not set.
}
}
session.publish(publisher);
If a subscriber is unable to decode a stream's media due to an incorrect encryption secret, the SubscriberListener.onError() event handler is called with an error that has the code set to ErrorCode.EncryptionSecretMismatch. 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 issue:
// Implementation of Subscriber.onError():
@Override
public void onError(SubscriberKit publisher, OpentokError opentokError) {
if (opentokError.getErrorCode() == ErrorCode.EncryptionSecretMismatch) {
// Activate a UI element communicating that there's been an encryption secret mismatch.
}
}
session.subscribe(subscriber);
If the application tries to subscribe without setting an encryption secret, the Subscriber.onError() event handler is called with an error that has the code set to ErrorCode.EncryptionSecretMissing.
If a subscriber encounters an internal error while decrypting a packet, the Subscriber.onError() event handler is called with an error that has the code set to ErrorCode.DecryptionInternalError.
Setting a secret in a session without end-to-end encryption
Note: This behavior is available starting with version 2.36.0 of the SDK.
If a session was not created with end-to-end encryption enabled, setting an encryption secret for it results in an ErrorCode.EncryptionNotEnabled error. Where the error surfaces depends on when the secret is set relative to connecting, publishing, and subscribing.
Setting the secret before connecting
Whether a session has end-to-end encryption enabled is only known once the client connects. If you call Session.setEncryptionSecret() before connecting, the call succeeds and the session connects normally. The error is reported when the client publishes or subscribes: calling Session.publish() or Session.subscribe() results in the SessionListener.onError() event handler being called with an error that has the code set to ErrorCode.EncryptionNotEnabled:
// Implementation of SessionListener.onError():
@Override
public void onError(Session session, OpentokError opentokError) {
if (opentokError.getErrorCode() == ErrorCode.EncryptionNotEnabled) {
// The application should communicate that end-to-end encryption
// is not enabled for this session.
}
}
session.setEncryptionSecret("encryption-secret");
session.connect(TOKEN);
// ...
session.publish(publisher);
Setting the secret after connecting
If you call Session.setEncryptionSecret() after the client has connected to a session without end-to-end encryption, the secret is not set and the SessionListener.onError() event handler is called with an error that has the code set to ErrorCode.EncryptionNotEnabled.
Setting the secret while publishing or subscribing
If you call Session.setEncryptionSecret() while the client is already publishing or subscribing, the call fails as described above, and every active publisher and subscriber is also removed from the session. Each one reports the error through its own onError() event handler — PublisherListener.onError() for publishers and SubscriberListener.onError() for subscribers — with the code set to ErrorCode.EncryptionNotEnabled:
// Implementation of PublisherListener.onError():
@Override
public void onError(PublisherKit publisher, OpentokError opentokError) {
if (opentokError.getErrorCode() == ErrorCode.EncryptionNotEnabled) {
// The publisher has been removed from the session.
}
}
// Implementation of SubscriberListener.onError():
@Override
public void onError(SubscriberKit subscriber, OpentokError opentokError) {
if (opentokError.getErrorCode() == ErrorCode.EncryptionNotEnabled) {
// The subscriber has been removed from the session.
}
}
Recovering from the error
The session remains valid after any of these errors. To publish or subscribe again, clear the secret by calling Session.setEncryptionSecret() with null. The same PublisherKit object can then be passed to Session.publish() again:
session.setEncryptionSecret(null);
session.publish(publisher);
Setting the encryption secret
End-to-end encrypted sessions are created using server APIs (see Enabling encryption using the REST API).
Before the client publishes or subscribes, call the [OTSession setEncryptionSecret:error:] method:
var error: OTError?
session.setEncryptionSecret("encryption-secret", error: &error)
if (error)
{
// Notify the user.
}
A valid secret is a string between 8 and 256 characters. You can change the secret by calling the Session.setEncryptionSecret() method again.
Setting an invalid secret will result in an InvalidEncryptionSecret error.
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.
If the client tries to connect to an end-to-end encrypted session and does not set the encryption secret before connecting, an error with the code set to EncryptionSecretMissing:
var error: OTError?
session.connect(withToken: token, error: &error)
if (error && (error.code ==EncryptionSecretMissing))
{
// Notify the user of the error connecting.
}
If a user tries to publish in an end-to-end encrypted session without having specified an encryption secret, calling the [OTSession publish:error:] method results in an error that has the code set to OTPublisherEncryptionSecretMissing. For the best user experience, the application should validate a user-supplied secret before publishing:
var error: OTError?
session.publish(publisher, error: &error)
if (error && (error.code == EncryptionSecretMissing))
{
// The application should communicate that the secret was not set.
}
If a subscriber is unable to decode a stream's media due to an incorrect encryption secret, the [OTSubscriberKitDelegate subscriber:didFailWithError:] message is sent with an error that has the code set to ErrorCode.EncryptionSecretMismatch. 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 issue:
// Implementation of [OTSubscriberKitDelegate subscriber:didFailWithError:]:
func subscriber(_ subscriber: OTSubscriberKit, didFailWithError error: OTError) {
if (error.code == EncryptionSecretMismatch) {
// Activate a UI element communicating that there's been an encryption secret mismatch.
}
}
var error: OTError?
session.subscribe(subscriber!, error: &error)
// ...
If a subscriber encounters an internal error while decrypting a packet, the [OTSubscriberKitDelegate subscriber:didFailWithError:] message is sent with an error that has the code set to OTSubscriberDecryptionInternalError.
Setting a secret in a session without end-to-end encryption
Note: This behavior is available starting with version 2.36.0 of the SDK.
If a session was not created with end-to-end encryption enabled, setting an encryption secret for it results in an "encryption not enabled" error. Where the error surfaces depends on when the secret is set relative to connecting, publishing, and subscribing.
Setting the secret before connecting
Whether a session has end-to-end encryption enabled is only known once the client connects. If you call OTSession.setEncryptionSecret(_:error:) before connecting, the call succeeds and the session connects normally. The error is reported when the client publishes or subscribes: calling OTSession.publish(_:error:) results in an error with the code set to OTPublisherErrorCode.encryptionNotEnabled, and calling OTSession.subscribe(_:error:) results in an error with the code set to OTSubscriberErrorCode.encryptionNotEnabled:
var error: OTError?
session.publish(publisher, error: &error)
if let error = error, error.code == Int(OTPublisherErrorCode.encryptionNotEnabled.rawValue) {
// The application should communicate that end-to-end encryption
// is not enabled for this session.
}
Setting the secret after connecting
If you call OTSession.setEncryptionSecret(_:error:) after the client has connected to a session without end-to-end encryption, the secret is not set and the method returns an error with the code set to OTSessionErrorCode.encryptionNotEnabled:
var error: OTError?
session.setEncryptionSecret("encryption-secret", error: &error)
if let error = error, error.code == Int(OTSessionErrorCode.encryptionNotEnabled.rawValue) {
// The application should communicate that end-to-end encryption
// is not enabled for this session.
}
Setting the secret while publishing or subscribing
If you call OTSession.setEncryptionSecret(_:error:) while the client is already publishing or subscribing, the call fails as described above, and every active publisher and subscriber is also removed from the session. The OTPublisherKitDelegate.publisher(_:didFailWithError:) method is called for each publisher with an error that has the code set to OTPublisherErrorCode.encryptionNotEnabled, and the OTSubscriberKitDelegate.subscriber(_:didFailWithError:) method is called for each subscriber with an error that has the code set to OTSubscriberErrorCode.encryptionNotEnabled.
Recovering from the error
The session remains valid after any of these errors. To publish or subscribe again, clear the secret by calling OTSession.setEncryptionSecret(_:error:) with nil. The same OTPublisherKit object can then be passed to OTSession.publish(_:error:) again:
var error: OTError?
session.setEncryptionSecret(nil, error: &error)
session.publish(publisher, error: &error)
Setting the encryption secret
End-to-end encrypted sessions are created using server APIs (see Enabling encryption using the REST API).
Before the client publishes or subscribes, call the [OTSession setEncryptionSecret:error:] method:
OTError *error = nil;
[_session setEncryptionSecret:@"encryption-secret" error:&error];
if (error)
{
// Notify the user.
}
A valid secret is a string between 8 and 256 characters. You can change the secret by calling the Session.setEncryptionSecret() method again.
Setting an invalid secret will result in an InvalidEncryptionSecret error.
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.
If the client tries to connect to an end-to-end encrypted session and does not set the encryption secret before connecting, an error with the code set to EncryptionSecretMissing:
OTError *error = nil;
[_session connectWithToken:kToken error:&error];
if (error && (error.code == EncryptionSecretMissing))
{
// Notify the user of the error connecting.
}
If a user tries to publish in an end-to-end encrypted session without having specified an encryption secret, calling the [OTSession publish:error:] method results in an error that has the code set to OTPublisherEncryptionSecretMissing. For the best user experience, the application should validate a user-supplied secret before publishing:
OTError *error = nil;
[_session publish:_publisher error:&error];
if (error && (error.code == OTPublisherEncryptionSecretMissing))
{
// The application should communicate that the secret was not set.
}
If a subscriber is unable to decode a stream's media due to an incorrect encryption secret, the [OTSubscriberKitDelegate subscriber:didFailWithError:] message is sent with an error that has the code set to ErrorCode.EncryptionSecretMismatch. 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 issue:
// Implementation of [OTSubscriberKitDelegate subscriber:didFailWithError:]:
- (void)subscriber:(OTSubscriberKit*)subscriber
didFailWithError:(OTError*)error
{
if (error && (error.code == EncryptionSecretMismatch)) {
// Activate a UI element communicating that there's been an encryption secret mismatch.
}
}
[_session subscribe:_subscriber error:&error];
// ...
If a subscriber encounters an internal error while decrypting a packet, the [OTSubscriberKitDelegate subscriber:didFailWithError:] message is sent with an error that has the code set to OTSubscriberDecryptionInternalError.
Setting a secret in a session without end-to-end encryption
Note: This behavior is available starting with version 2.36.0 of the SDK.
If a session was not created with end-to-end encryption enabled, setting an encryption secret for it results in an "encryption not enabled" error. Where the error surfaces depends on when the secret is set relative to connecting, publishing, and subscribing.
Setting the secret before connecting
Whether a session has end-to-end encryption enabled is only known once the client connects. If you call [OTSession setEncryptionSecret:error:] before connecting, the call succeeds and the session connects normally. The error is reported when the client publishes or subscribes: calling [OTSession publish:error:] results in an error with the code set to OTPublisherEncryptionNotEnabled, and calling [OTSession subscribe:error:] results in an error with the code set to OTSubscriberEncryptionNotEnabled:
OTError *error = nil;
[_session publish:_publisher error:&error];
if (error && (error.code == OTPublisherEncryptionNotEnabled))
{
// The application should communicate that end-to-end encryption
// is not enabled for this session.
}
Setting the secret after connecting
If you call [OTSession setEncryptionSecret:error:] after the client has connected to a session without end-to-end encryption, the secret is not set and the method returns an error with the code set to OTSessionEncryptionNotEnabled:
OTError *error = nil;
[_session setEncryptionSecret:@"encryption-secret" error:&error];
if (error && (error.code == OTSessionEncryptionNotEnabled))
{
// The application should communicate that end-to-end encryption
// is not enabled for this session.
}
Setting the secret while publishing or subscribing
If you call [OTSession setEncryptionSecret:error:] while the client is already publishing or subscribing, the call fails as described above, and every active publisher and subscriber is also removed from the session. The [OTPublisherKitDelegate publisher:didFailWithError:] message is sent to each publisher with an error that has the code set to OTPublisherEncryptionNotEnabled, and the [OTSubscriberKitDelegate subscriber:didFailWithError:] message is sent to each subscriber with an error that has the code set to OTSubscriberEncryptionNotEnabled.
Recovering from the error
The session remains valid after any of these errors. To publish or subscribe again, clear the secret by calling [OTSession setEncryptionSecret:error:] with nil. The same OTPublisherKit object can then be passed to [OTSession publish:error:] again:
OTError *error = nil;
[_session setEncryptionSecret:nil error:&error];
[_session publish:_publisher error:&error];
Setting the encryption secret
End-to-end encrypted sessions are created using server APIs (see Enabling encryption using the REST API).
Before the client publishes or subscribes, call the Session.SetEncryptionSecret() method:
Session.SetEncryptionSecret("encryption-secret");
Session.Connect(TOKEN);
A valid secret is a string between 8 and 256 characters. You can change the secret by calling the Session.SetEncryptionSecret() method again.
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.
If a client tries to connect to an end-to-end encrypted session without setting an encryption secret, the Session.Error event is sent with an error code set to ErrorCode.EncryptionSecretMissing:
private void Session_Error(object sender, ErrorEventArgs error)
{
if (Error.ErrorCode == ErrorCode.EncryptionSecretMissing) {
// Notify the user that they cannot join the session
}
}
Session.Error += Session_Error;
Session.Connect(TOKEN);
If a user tries to publish in an end-to-end encrypted session without having specified an encryption secret, calling the Session.Publish() function results in the Publisher.Error event being sent with an error that has the code set to ErrorCode.EncryptionInternalError. For the best user experience, the application should validate a user-supplied secret before calling the Session.Publish() method:
private void Publisher_Error(object sender, ErrorEventArgs error)
{
if (Error.ErrorCode == ErrorCode.EncryptionInternalError) {
// The application should communicate that the secret was not set.
}
}
Publisher.Error += Publisher_Error;
Session.Publish(Publisher);
If a subscriber is unable to decode a stream's media due to an incorrect encryption secret, the Subscriber.Error event is sent with an error that has the code set to ErrorCode.EncryptionSecretMismatch. 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 issue:
private void Subscriber_Error(object sender, ErrorEventArgs error)
{
if (Error.ErrorCode == ErrorCode.EncryptionSecretMismatch) {
// Activate a UI element communicating that there's been an encryption secret mismatch.
}
}
Subscriber.Error += Subscriber_Error;
Session.Subscribe(Subscriber);
If a subscriber encounters an internal error while decrypting a packet, the Subscriber.Error event is sent with an error that has the code set to ErrorCode.DecryptionInternalError.
Setting a secret in a session without end-to-end encryption
Note: This behavior is available starting with version 2.36.0 of the SDK.
If a session was not created with end-to-end encryption enabled, setting an encryption secret for it results in an ErrorCode.EncryptionNotEnabled error. Where the error surfaces depends on when the secret is set relative to connecting, publishing, and subscribing.
Setting the secret before connecting
Whether a session has end-to-end encryption enabled is only known once the client connects. If you call Session.SetEncryptionSecret() before connecting, the call succeeds and the session connects normally. The error is reported when the client publishes or subscribes: calling Session.Publish() or Session.Subscribe() throws an OpenTokException with the ErrorCode set to ErrorCode.EncryptionNotEnabled:
try
{
Session.Publish(Publisher);
}
catch (OpenTokException ex) when (ex.ErrorCode == ErrorCode.EncryptionNotEnabled)
{
// The application should communicate that end-to-end encryption
// is not enabled for this session.
}
Setting the secret after connecting
If you call Session.SetEncryptionSecret() after the client has connected to a session without end-to-end encryption, the secret is not set and the method throws an OpenTokException with the ErrorCode set to ErrorCode.EncryptionNotEnabled:
try
{
Session.SetEncryptionSecret("encryption-secret");
}
catch (OpenTokException ex) when (ex.ErrorCode == ErrorCode.EncryptionNotEnabled)
{
// The application should communicate that end-to-end encryption
// is not enabled for this session.
}
Setting the secret while publishing or subscribing
If you call Session.SetEncryptionSecret() while the client is already publishing or subscribing, the call fails as described above, and every active publisher and subscriber is also removed from the session. The Publisher.Error event is sent for each publisher, and the Subscriber.Error event is sent for each subscriber, with an error that has the code set to ErrorCode.EncryptionNotEnabled.
Recovering from the error
The session remains valid after any of these errors. To publish or subscribe again, clear the secret by calling Session.SetEncryptionSecret() with null. The same Publisher object can then be passed to Session.Publish() again:
Session.SetEncryptionSecret(null);
Session.Publish(Publisher);
Setting the encryption secret
End-to-end encrypted sessions are created using server APIs (see Enabling encryption using the [REST API](/video/guides/end-to-end-encryption/overview#enabling-encryption-using-the-rest-api)).Before the client publishes or subscribes, call the otc_session_set_encryption_secret() function:
otc_session_set_encryption_secret(session, secret);
otc_session_connect(session, TOKEN);
A valid secret is a string between 8 and 256 characters. You can change the secret by calling the otc_session_set_encryption_secret() function again.
Passing an invalid secret will result in an OTC_SESSION_INVALID_ENCRYPTION_SECRET error.
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.The new error code is OTC_SESSION_INVALID_ENCRYPTION_SECRET and will be returned as the result code of the set_encryption_secret method, not in the on_error callback.
If a client tries to set an invalid encryption secret for a session, the otc_session_callbacks.on_error() returns an error code set to OTC_SESSION_INVALID_ENCRYPTION_SECRET. In the following example, a session is initialized with an empty (and thus invalid) encryption secret:
int result = otc_session_set_encryption_secret(session, "");
if (result == OTC_SESSION_INVALID_ENCRYPTION_SECRET) {
// Report error...
}
If a user tries to publish in an end-to-end encrypted session without having specified an encryption secret, calling the otc_session_publish() function results in the otc_publisher_callbacks.on_error() function being called with an error that has the code set to OTC_SESSION_ENCRYPTION_SECRET_MISSING. For the best user experience, the application should validate a user-supplied secret before calling the otc_session_publish() function:
static void on_publisher_error(otc_publisher *publisher,
void *user_data,
const char* error_string,
enum otc_publisher_error_code error_code) {
if (otc_publisher_error_code == "OTC_SESSION_ENCRYPTION_SECRET_MISSING") {
// The application should communicate that the secret was not set.
}
}
struct otc_publisher_callbacks publisher_callbacks = {0};
publisher_callbacks.on_error = on_publisher_error;
session = otc_session_new(API_KEY, SESSION_ID, &session_callbacks);
otc_publisher *publisher = otc_publisher_new("Joe",
nullptr,
&publisher_callbacks);
otc_session_publish(session, publisher);
If a subscriber is unable to decode a stream's media due to an incorrect encryption secret, the subscriber_callbacks.on_error() function is called with an error that has the code set to OTC_SUBSCRIBER_ENCRYPTION_SECRET_MISMATCH. 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 issue:
static void on_subscriber_error(otc_subscriber *subscriber,
void *user_data,
const char* error_string,
enum otc_subscriber_error_code error_code) {
if (otc_subscriber_error_code == "OTC_SUBSCRIBER_ENCRYPTION_SECRET_MISMATCH") {
// Activate a UI element communicating that there's been an encryption secret mismatch.
}
}
struct otc_subscriber_callbacks subscriber_callbacks = {0};
subscriber_callbacks.on_error = on_subscriber_error;
otc_subscriber *subscriber = otc_subscriber_new(stream,
&subscriber_callbacks);
otc_session_subscribe(session, subscriber);
If a subscriber encounters an internal error while decrypting a packet, the subscriber_callbacks.on_error() function is called with an error that has the code set to OTC_SUBSCRIBER_DECRYPTION_INTERNAL_ERROR.
Setting the encryption secret
End-to-end encrypted sessions are created using server APIs (see Enabling encryption using the REST API).
Before the client publishes or subscribes, call the otc_session_set_encryption_secret() method:
otc_session_set_encryption_secret(session, secret);
otc_session_connect(session, TOKEN);
A valid secret is a string between 8 and 256 characters. You can change the secret by calling the otc_session_set_encryption_secret() function again.
Setting an invalid secret will result in an OTC_SESSION_INVALID_ENCRYPTION_SECRET error.
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.
The new error code is OTC_SESSION_INVALID_ENCRYPTION_SECRET and will be returned as the result code of the set_encryption_secret method, not in the on_error callback.
If a client tries to set an invalid encryption secret for a session, the otc_session_callbacks.on_error() returns an error code set to OTC_SESSION_INVALID_ENCRYPTION_SECRET. In the following example, a session is initialized with an empty (and thus invalid) encryption secret:
int result = otc_session_set_encryption_secret(session, "");
if (result == OTC_SESSION_INVALID_ENCRYPTION_SECRET) {
// Report error...
}
If a user tries to publish in an end-to-end encrypted session without having specified an encryption secret, calling the otc_session_publish() function results in the otc_publisher_callbacks.on_error() function being called with an error that has the code set to OTC_SESSION_ENCRYPTION_SECRET_MISSING. For the best user experience, the application should validate a user-supplied secret before calling the otc_session_publish() function:
static void on_publisher_error(otc_publisher *publisher,
void *user_data,
const char* error_string,
enum otc_publisher_error_code error_code) {
if (otc_publisher_error_code == OTC_SESSION_ENCRYPTION_SECRET_MISSING) {
// The application should communicate that the secret was not set.
}
}
struct otc_publisher_callbacks publisher_callbacks = {0};
publisher_callbacks.on_error = on_publisher_error;
session = otc_session_new(API_KEY, SESSION_ID, &session_callbacks);
otc_publisher *publisher = otc_publisher_new("Joe",
nullptr,
&publisher_callbacks);
otc_session_publish(session, publisher);
If a subscriber is unable to decode a stream's media due to an incorrect encryption secret, the subscriber_callbacks.on_error() function is called with an error that has the code set to OTC_SUBSCRIBER_ENCRYPTION_SECRET_MISMATCH. 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 issue:
static void on_subscriber_error(otc_subscriber *subscriber,
void *user_data,
const char* error_string,
enum otc_subscriber_error_code error_code) {
if (otc_subscriber_error_code == OTC_SUBSCRIBER_ENCRYPTION_SECRET_MISMATCH) {
// Activate a UI element communicating that there's been an encryption secret mismatch.
}
}
struct otc_subscriber_callbacks subscriber_callbacks = {0};
subscriber_callbacks.on_error = on_subscriber_error;
otc_subscriber *subscriber = otc_subscriber_new(stream,
&subscriber_callbacks);
otc_session_subscribe(session, subscriber);
If a subscriber encounters an internal error while decrypting a packet, the subscriber_callbacks.on_error() function is called with an error that has the code set to OTC_SUBSCRIBER_DECRYPTION_INTERNAL_ERROR.
Setting a secret in a session without end-to-end encryption
Note: This behavior is available starting with version 2.36.0 of the SDK.
If a session was not created with end-to-end encryption enabled, setting an encryption secret for it results in an "encryption not enabled" error. Where the error surfaces depends on when the secret is set relative to connecting, publishing, and subscribing.
Setting the secret before connecting
Whether a session has end-to-end encryption enabled is only known once the client connects. If you call otc_session_set_encryption_secret() before connecting, the call succeeds and the session connects normally. The error is reported when the client publishes or subscribes: the otc_session_publish() function returns OTC_PUBLISHER_ENCRYPTION_NOT_ENABLED, and the otc_session_subscribe() function returns OTC_SUBSCRIBER_ENCRYPTION_NOT_ENABLED:
otc_status result = otc_session_publish(session, publisher);
if (result == OTC_PUBLISHER_ENCRYPTION_NOT_ENABLED) {
// The application should communicate that end-to-end encryption
// is not enabled for this session.
}
Setting the secret after connecting
If you call otc_session_set_encryption_secret() after the client has connected to a session without end-to-end encryption, the secret is not set and the function returns OTC_SESSION_ENCRYPTION_NOT_ENABLED:
otc_status result = otc_session_set_encryption_secret(session, secret);
if (result == OTC_SESSION_ENCRYPTION_NOT_ENABLED) {
// The application should communicate that end-to-end encryption
// is not enabled for this session.
}
Setting the secret while publishing or subscribing
If you call otc_session_set_encryption_secret() while the client is already publishing or subscribing, the call fails as described above, and every active publisher and subscriber is also removed from the session. The otc_publisher_callbacks.on_error() function is called for each publisher with an error that has the code set to OTC_PUBLISHER_ENCRYPTION_NOT_ENABLED, and the otc_subscriber_callbacks.on_error() function is called for each subscriber with an error that has the code set to OTC_SUBSCRIBER_ENCRYPTION_NOT_ENABLED.
Recovering from the error
The session remains valid after any of these errors. To publish or subscribe again, clear the secret by calling otc_session_set_encryption_secret() with NULL. The same otc_publisher object can then be passed to otc_session_publish() again:
otc_session_set_encryption_secret(session, NULL);
otc_session_publish(session, publisher);