myApps Protocol

The myApps protocol is the WebSocket protocol used by the myApps web client to talk to the PBX.

Messages

The following messages can be used without logging-in:

Login messages

The following messages are only allowed after successfully logging-in.

Objects - recurring definitions

Message Flow

Session and user authentication with the "digest method".

This message flow shows an attempt to login using session data from previous successful login. In this case the attempt fails with "Session expired" error. The following login with user credentials succeeds after a 2FA confirmation.

AppLogin Sequence Diagramm

User authentication with the "oauth2" method.

This message flow shows a login flow using OAuth2 and 2FA. In that case the username and password are not verified by the PBX, but by an external ID provider. The username is taken from the ID token and sent from the PBX to the myApps client. Instead of the password that is unknown by the PBX and the myApps client, an ECDHE handshake is done in order to create a shared secret. That shared secret is used instead of the user's password.

AppLogin Sequence Diagramm

Messages

Base Message

The base message format consists only of the property mt.

{
    "mt": string
}

mt
The type of the message.
CheckBuild

Sent by the client.

{
    "mt": "CheckBuild",
    "url": string,
    "always": boolean
}
url
The URL of the used HTML page.
always
true, if the CheckBuildResult should trigger a redirect in any case. undefined otherwise.
CheckBuildResult

Sent by the PBX as a response to the CheckBuild message.

{
    "mt": "CheckBuildResult",
    "url": string,
    "version": string,
    "build": string,
    "launcherUpdateBuild": string,
}
url
Given, if a redirect is needed. The new URL should be loaded instead of the URL from the CheckBuild message.
build
The version of the PBX firmware, e.g. "13r3".
build
The build number of the PBX firmware.
launcherUpdateBuild
The build number of the myApps launcher that shall be used for software updates.
appStoreUrl
The URL of the app store that shall be used for software updates.
SubscribeRegister

Sent by the client to subscribe for UpdateRegister messages.

{
    "mt": "SubscribeRegister"
}
UpdateRegister

Sent by the PBX. Contains URLs for user registration and password resets to be displayed on the login page.

{
    "mt": "UpdateRegister",
    "signup": string,
    "reset": string,
    "profile": profile
}
signup
URL for creating a new user account on the PBX.
reset
URL for resetting a forgotten user password.
profile
Name of the app that allows changing user settings.
LoginInfo

Sent by the client.

This message can be used to query the available authentication methods on the PBX. The PBX answers with the LoginInfoResult message.

{
    "mt": "LoginInfo"
}
LoginInfoResult

Sent by the PBX.

This message is sent by the PBX as an answer to the LoginInfo message and contains the activated authentication methods.

Depending on the activated methods for login type "user" the client should display different elements in the login screen.

{
    "mt": "LoginInfo",
    "user": {
        "digest": bool,
        "ntlm": bool,
        "oauth2": bool
    },
    "session": {
        "digest": bool
    }
}
user
An object containing the available authentication methods for login type "user".
session
An object containing the available authentication methods for login type "session".
digest
true, if the method "digest" is available.
ntlm
true, if the method "ntlm" is available.
oauth2
true, if the method "oauth2" is available.
Login

Sent by the client.

Methods "digest" and "ntlm".

During the login procedure the Login message is sent twice. The first time it does not include any credentials and is responded with an Authenticate message including a challenge.

{
    "mt": "Login",
    "type": string,
    "userAgent": string
}

The second time it is sent with the actual login data that includes a user name and a response in the form of a digest.

{
    "mt": "Login",
    "type": string,
    "method": string,
    "username": string,
    "nonce": string,
    "response": string,
    "userAgent": string
}

Method "oauth2"

When using Using OAuth2 the login message is only sent once. It does not contain the username and response parameter, but an additional ECDHE key share.

{
    "mt": "Login",
    "type": string,
    "method": string,
    "nonce": string,
    "keyShare": string,
    "userAgent": string
}

If the authentication was successful the PBX will respond with LoginResult. If two-factor authentication is enabled the PBX will first send an Authorize and wait with the LoginResult until the session has been authorized over a second channel.

type
"user" for login with user credentials. This will create a persistent session that can be resumed for subsequent logins.
"session" for login with session credentials that were created during a previous login with user credentials.
method
"digest", "ntlm" or "oauth2".
Must be the same method as requested in the Authenticate message.
username
The SIP URI of the user for type "user".
The session ID for type "session".
undefined for method "oauth2".
nonce
A 16-byte hexstring, encoding 8 random bytes chosen by the client software.
Nonces must be unique and should not be re-used for subsequent connections.
response
A digest calculated to verify the knowledge of the shared secret that can be either the user password or the session password, depending on the login type.
For type "digest"
Hexstring(SHA256(innovaphoneAppClient:<type>:<domain>:<username>:<password>:<nonce>:<challenge>))
For type "ntlm"
Hexstring(NtlmResponse(<username>,<password>))
For method "oauth2"
undefined
keyShare
For method "oauth2" only. An 64 byte ECDHE key share encoded as a hexstring of 128 characters. The used curve is secp256r1. The used point format is uncompressed. The point format (04) is not part of the encoded hexstring.
The shared secret is calculated like that:
Hexstring(ECDH(secp256r1, <private-key>, <Login.keyShare>, <LoginResult.info.keyShare>))
or
Hexstring(ECDH(secp256r1, <private-key>, <Login.keyShare>, <Redirect.info.keyShare>))
userAgent
A string describing the used software for this connection, like "myApps (Windows)".
Authenticate

Sent by the PBX as a response to the initial Login message.

After the client sent the first Login message without credentials, the PBX sends the Authenticate message. It includes the parameters (method, challenge and domain) that are needed to calculate the fields for the second Login message for the actual authentication.

{
    "mt": "Authenticate",
    "type": string,
    "method": string,
    "domain": string,
    "url": string,
    "challenge": string
}
type
"user" or "session".
Same type as requested by the client in the initial Login message.
method
"digest" or "ntlm".
Defines the hash calculation method that shall be used in the subsequent Login message.
domain
The domain of the PBX.
url
Method "oauth2" only. The URL of the login page of the ID provider that shall be displayed.
challenge
An opaque string.
Authorize

Sent by the PBX as a response to the second Login message.

This message is used together with two-factor authentication with the "user" type login. At this point the user password was successfully validated by the PBX but the user needs to complete the second factor of the authentication on a different channel. If that has happened the PBX proceeds by sending the LoginResult message.

{
    "mt": "Authorize",
    "code": integer
}
Code
A security number that should be displayed to the user. The same number is presented to the user on the second channel, so the user can be sure he or she confirms the right session.
LoginResult

Sent by the PBX as a response to the second Login message.

The message indicates that the login was successful and includes additional information for the client.

{
    "mt": "LoginResult",
    "info": Info,
    "digest": string
}
info
A Json Object with additional information. For the digest calculation this must be json encoded without any unnecessary white space and no unnecessary escaping. This is the encoding done by the json_io library of the SDK, by the Javascript JSON.stringify function or by PHP json_encode($input, JSON_UNESCAPED_UNICODE)
digest
A digest calculated to verify the knowledge of the shared secret and to protect the integrify of the included info structure. The shared secret is different, depending on the login type and method:
the user password
for login type "user" and methods "digest" and "ntlm"
the ECDHE shared secret
for login type "user" and method "oauth2"
<password> := Hexstring(ECDH(secp256r1, <private-key>, <Login.keyShare>, <LoginResult.info.keyShare>))
the session password
for login type "session" and method "digest"
It also protects the integrity of the included info structure.
Hexstring(SHA256(innovaphoneAppClient:loginresult:<domain>:<username>:<password>:<nonce>:<challenge>:<info>))

If the login failed the message contains error information instead.

{
    "mt": "LoginResult",
    "error": integer,
    "errorText": string
}
Redirect

Sent by the PBX as a response to the Login message.

The message indicates that the login was successful, but the user is on a different PBX, so a redirect should be done.

{
    "mt": "Redirect",
    "info": Info,
    "digest": string
}
info
A Json Object with additional information. For the digest calculation this must be json encoded without any unnecessary white space and no unnecessary escaping. This is the encoding done by the json_io library of the SDK, by the Javascript JSON.stringify function or by PHP json_encode($input, JSON_UNESCAPED_UNICODE).
The redirect should be done to the host contained in the Info part.
digest
A digest calculated to verify the knowledge of the shared secret and to protect the integrify of the included info structure. The shared secret is different, depending on the login type and method:
the user password
for login type "user" and methods "digest" and "ntlm"
the ECDHE shared secret
for login type "user" and method "oauth2"
<password> := Hexstring(ECDH(secp256r1, <private-key>, <Login.keyShare>, <Redirect.info.keyShare>))
the session password
for login type "session" and method "digest"
It also protects the integrity of the included info structure.
Hexstring(SHA256(innovaphoneAppClient:redirect:<username>:<password>:<nonce>:<challenge>:<info>))
LoginCancel

Sent by the client to cancel a started login with method "oauth2". The PBX responds with LoginResult with an error.

{
    "mt": "LoginCancel"
}
Logout

Sent by the client to logout the current session.

{
    "mt": "Logout"
}
LogoutResult

Sent by the PBX if the current session was logged-out. This could be as a response to the Logout message or unsolicitated. The client should delete all information that is related to the session.

{
    "mt": "LogoutResult"
}
StandbyBack

The login was accepted by a standby PBX before. But now the original PBX is back. The PBX terminates the connection after that message. The client should reconnect and start its normal login procedure using the same session.

{
    "mt": "StandbyBack"
}
Disconnect

The PBX sends this message when it is turned off. The PBX terminates the connection after that message. The client should reconnect and start its normal login procedure using the same session.

{
    "mt": "Disconnect"
}
UpdateUser

Sent by the PBX. Contains the details of the logged-in user.

{
    "mt": "UpdateUser",
    "user": User
}
SessionAdded

Sent by the PBX if a login-session for the user has been added. If the session has the needsAuthorization flag set, the client should display the code to the user and ask if the session should be authorized. Depending on the decision by the user the AuthorizeSession or DeleteSession should be sent.

{
    "mt": "SessionAdded",
    "id": string,
    "info": SessionInfo
}
SessionUpdated

Sent by the PBX if a login-session for the user was updated. If the session has the needsAuthorization flag set, the client should display the code to the user and ask if the session should be authorized. Depending on the decision by the user the AuthorizeSession or DeleteSession should be sent.

{
    "mt": "SessionUpdated",
    "id": string,
    "info": SessionInfo
}
SessionDeleted

Sent by the PBX if a login-session for the user has been deleted. Connections in the context of the deleted session will receive the LogoutResult message afterwards.

{
    "mt": "SessionDeleted",
    "id": string
}
AuthorizeSession

Sent by the client to complete two-factor authentication for sessions that are waiting for the second factor. Only own sessions (of the same PBX user) can be authorized.

{
    "mt": "AuthorizeSession",
    "id": string
}
DeleteSession

Sent by the client to reject a session that is waiting for second factor authentication or to remotely logout a session. Only own sessions (of the same PBX user) can be deleted.

{
    "mt": "DeleteSession",
    "id": string
}
SetSessionInfo

Sent by the client to store parameters about the session in the PBX.

{
    "mt": "SetSessionInfo",
    "token": string,
    "wake": [string]
}
token
The push token for this session. Used on smartphones.
wake
An array of strings containing the supported wake types. Allowed values are "phone" and "chat".
SubscribeApps

Sent by the client to subscribe for UpdateApps messages. The subscription is valid until a LogoutResult message is received.

{
    "mt": "SubscribeApps"
}
UpdateApps

Sent by the PBX. Contains information about all the apps that the user has access to.

{
    "mt": "UpdateApps",
    "apps": [App],
    "deviceApps": [App],
    "selected": string
}
apps
An array of all available apps.
deviceApps
An array of the apps that can be attached to a device at the user object - that is the phone apps.
selected
A comma separated list of the app links on the home screen.
SetApps

Sent by the client to store the apps the user selected for his or her home screen.

{
    "mt": "SetApps",
    "home": string
}
home
A comma-separated list of the app links on the home screen.
Wake

Sent by the PBX. An event has occurred that requires the client to start some apps. For example this is needed on incoming phone calls when the phone app is not running yet. The client starts an app if

{
    "mt": "Wake",
    "type": string,
    "hw": string,
    "incoming": boolean
}
type
"phone" for phone calls, "chat" for incoming chat messages.
hw
The device on which a phone call is ringing.
incoming
True for incoming calls.
AppGetLogin

Sent by the client get an authentication for a given app.

{
    "mt": "AppGetLogin",
    "src": string,
    "app": string,
    "challenge": string
}
app
The SIP URI of the app.
challenge
The challenge given by the app service.
AppGetLoginResult

Sent by the PBX as a response to the AppGetLogin message. It contains the info that shall be presented to the app service to prove the successful login.

{
    "mt": "AppGetLoginResult",
    "src": string,
    "domain": string,
    "sip": string,
    "guid": string,
    "dn": string,
    "pbxObj": string,
    "app": string,
    "info": AppLoginInfo,
    "digest": string,
    "salt": string,
    "key": string,
    "error": unsigned,
    "errorText": string
}
domain
The domain of the logged in user
sip
The sip user part of the logged in user.
guid
The GUID of the user, if available
dn
The display name of the user, if available
pbxObj
Used for some Apis on the PBX to address a PBX Object. Not included in the digest calculation
info
A Json Object with additional information. For the digest calculation this must be json encoded without any unnecessary white space and no unnecessary escaping. This is the encoding done by the json_io library of the SDK, by the Javascript JSON.stringify function or by PHP json_encode($input, JSON_UNESCAPED_UNICODE)
digest
The digest calculated to verify the knowledge of the shared secret. It is calculated as SHA256 hash over the string
<app>:<domain>:<sip>:<guid>:<dn>:<info>:<challenge>:<password>
salt
A salt used for the session key.
key
The session key that can be used for encrypted messages between the app and the app service using the AppWebsocket library.
error
Set if the login was unsuccessful.
errorText
A text describing what went wrong during the login.
SetUserActivity

Sent by the client to publish the user activity (active, inactive) in the im: presence at the user object.

{
    "mt": "SetUserActivity",
    "inactive": boolean
}
inactive
True, if the user is inactive. False, if the user is active.
SetOwnPresence

Sent by the client to publish the users activity and note in the tel: presence at the user object.

{
    "mt": "SetOwnPresence",
    "activity": string,
    "note": string
}
activity
The presence activity. Allowed values are "", "away", "busy", "dnd".
note
A free text defined by the user.
UpdateOwnPresence

Sent by the PBX if the own presence has changed.

{
    "mt": "UpdateOwnPresence",
    "presence": [Presence]
}
SubscribePresence

Starts a presence subscription for a given SIP URI or phone number. The PBX will start sending UpdatePresence messages for that endpoint.

{
    "mt": "SubscribePresence",
    "sip": string,
    "num": string
}
sip
The SIP URI of the endpoint to be monitored.
num
The phone number of the endpoint to be monitored.
UnsubscribePresence

Stops a presence subscription for a given SIP URI or phone number. The PBX will stop sending UpdatePresence messages for that endpoint.

{
    "mt": "UnsubscribePresence",
    "sip": string,
    "num": string
}
sip
The SIP URI of the endpoint.
num
The phone number of the endpoint.
UpdatePresence

Send by the PBX if the presence of the monitored endpoint has changed.

{
    "mt": "UpdatePresence",
    "sip": string,
    "num": string,
    "up": boolean,
    "ep": {
        "sip": string,
        "dn": string,
        "num": string,
        "email": string,
        "url": string,
        "type": string
    },
    "presence": [Presence]
}
sip
The SIP URI of the endpoint.
num
The phone number of the endpoint.
up
True, if the monitor is connected. False otherwise.
ep
The details of the remote endpoint.
presence
An array containing presence items.
SubscribeDialog

Starts a dialog info subscription for a given SIP URI or phone number. The PBX will start sending DialogInfo messages for that endpoint.

{
    "mt": "SubscribeDialog",
    "sip": string,
    "num": string
}
sip
The SIP URI of the endpoint to be monitored.
num
The phone number of the endpoint to be monitored.
UnsubscribeDialog

Stops a dialog info subscription for a given SIP URI or phone number. The PBX will stop sending DialogInfo messages for that endpoint.

{
    "mt": "UnsubscribeDialog",
    "sip": string,
    "num": string
}
sip
The SIP URI of the endpoint.
num
The phone number of the endpoint.
DialogInfo

Sent by the PBX if a call of the monitored endpoint has changed its state. Note that the client needs to keep track of the current active call. If a DialogInfo for an unknown call id is received the call needs to be added to the local state. If the deleted flag is set, the calls must be removed again from the local state.

{
    "mt": "DialogInfo",
    "sip": string,
    "num": string,
    "callId": string,
    "confId": string,
    "remote": {
        "sip": string,
        "dn": string,
        "num": string
    },
    "state": {
        "name": string,
        "outgoing": boolean,
        "hold": boolean,
        "held": boolean,
        "waiting": boolean
    },
    "deleted": boolean
}
sip
The SIP URI of the endpoint.
num
The phone number of the endpoint.
callId
A unique ID for the call.
confId
The conference ID of the call. Many calls with the same conference ID belong together.
remote
Details about the remote endpoint.
state
Details about the call state.
deleted
True, if the call has ended and should be removed from the local state.

Objects

User
{
    "domain": string,
    "sip": string,
    "guid": string,
    "dn": string,
    "num": string,
    "email": string
}

The info object is generated by the PBX. It contains more information about the user.

domain
The domain name of the user.
sip
The SIP URI of the user.
guid
The GUID of the user object.
dn
The display name of the user object.
num
The phone number of the user object.
email
The email address of the user object.
Info
{
    "host": string,
    "domain": string,
    "sip": string,
    "guid": string,
    "dn": string,
    "num": string,
    "email": string,
    "session": Session,
    "keyShare": string,
    "alt": string,
    "altHttp": string
}

The info object is generated by the PBX when a user logs in. It contains more information about the user and optional information about the session that has been created during the login.

host
The target host name for the redirect.
Only present when used in the Redirect message.
http
The target HTTP port name for the redirect.
Only present when used in the Redirect message.
The target HTTPS port name for the redirect.
https
Only present when used in the Redirect message.
The target PBX module name for the redirect.
mod
Only present when used in the Redirect message.
domain
The domain name of the user.
sip
The SIP URI of the user.
guid
The GUID of the user object.
dn
The display name of the user object.
num
The phone number of the user object.
email
The email address of the user object.
session
A Session object containing session credentials.
keyShare
For method "oauth2" only. An 64 byte ECDHE key share encoded as a hexstring of 128 characters. The used curve is secp256r1. The used point format is uncompressed. The point format (04) is not part of the encoded hexstring.
The shared secret is calculated like that:
Hexstring(ECDH(secp256r1, <private-key>, <Login.keyShare>, <LoginResult.info.keyShare>))
or
Hexstring(ECDH(secp256r1, <private-key>, <Login.keyShare>, <Redirect.info.keyShare>))
alt
Only present when used in the LoginResult message.
The alternative PBX of the current PBX when using HTTPS.
A string in the format host:port/module-name, e.g. standby.example.com:4433/PBX0
altHttp
Only present when used in the LoginResult message.
The alternative PBX of the current PBX when using HTTP.
A string in the format host:port/module-name, e.g. standby.example.com:8080/PBX0
Session
{
    "usr": string,
    "pwd": string
}

During logins of type "user" a persistent session is created. This structure contains the encrypted credentials of this session. They are used for encrypting selected attributes of messages. Also, they are used for subsequent logins of type "session".

usr
The encrypted session username.
Hexstring(RC4(innovaphoneAppClient:usr:<nonce>:<password>, <session-username>))
pwd
The encrypted session password.
Hexstring(RC4(innovaphoneAppClient:pwd:<nonce>:<password>, <session-password>))
SessionInfo
{
    "id": string,
    "current": boolean,
    "userAgent": string,
    "timestamp": unsigned,
    "code": unsigned,
    "needsAuthorization": boolean
}

An object representing a persistent login session of the user.

id
The session id.
current
True if it is the session that belongs to the current websocket connection.
userAgent
The user agent string that is the browser name or "myApps for Windows", "myApps for iOS", etc.
timestamp
Timestamp of the last login or update of that session.
code
The authorization code for two-factor authentication. It is displayed to the user for telling own and malicious pending logins apart.
needsAuthorization
True if two-factor authentication is activated and the session was not confirmed yet using a second factor.
App
{
    "name": string,
    "title": string,
    "text": string,
    "url": string,
    "inline": boolean,
    "website": boolean,
    "info": AppInfo
}

An object representing an app.

name
The name / SIP URI of the app.
title
The display name of the app.
text
A description about the app defined at the user object.
url
The base URL of the app (without .htm).
inline
Obsolete.
website
If true the app is just a plain website. The client should not send any windows messages to the app or pass any URL parameters.
info
Additional info from the app service.
AppInfo
{
    "hidden": boolean,
    "presence": boolean,
    "apis": {
        string: object,
        ...
    },
    "wake": [string]
}

Additional info about the properties of an app. This info is dynamic info from the app service.

hidden
If true, the app should be opened only in the background and shall not be displayed to the user. This mechanism is used for apps that provide client APIs but no UI.
presence
The app answers presence subscriptions. The client should establish presence subscriptions for home screen items of that app to retrieve presence info like badge counts.
apis
An object containing all client APIs provided by the app. The key represents the API identifier (like com.innovaphone.search) and the object is the API provider info (defined by the Client API).
wake
An array of wake type identifiers. Depending on the contained wake types the client should wake up the app when a Wake message containing the same wake type is received.
phone
Phone calls
chat
Chat messages
AppLoginInfo
{
    "appobj": string,
    "appdn": string,
    "appurl": string,
    "cn": string,
    "unlicensed": boolean,
    "apps": [AppLoginInfoApp]
}

The info object is generated by the PBX when the App is requesting a login for an App Service. It contains more information about the user.

appobj
The sip/h323 id of the App Object in the PBX which grants the access
appdn
The display name of the App Object in the PBX which grants the access
appdn
The URL configured at the App Object in the PBX which grants the access. This can be used to determine the URL under which the app services is accessible.
cn
The cn (Long Name) of the user logging in
unlicensed
Present and true if the App is running in an unlicensed mode.
apps
Array of Apps to which this user has granted access
AppLoginInfoApp
{
    "name": string
}
Info about the App.
name
The sip/h323 identifier of the App Object
Presence
{
    "contact": string,
    "status": string,
    "activity": string,
    "note": string
}
contact
A string defining the type of the presence. Typical values are:
tel:
The presence set by the user.
im:
Automatically created by the PBX. The status attribute contains the online state of the user.
calendar:
Automatically created by a calendar app like the innovaphone Calendar.
status
Tells if the user can be contacted using the given contact. Possible values are "open", "closed".
activity
The presence activity. Typical values are "" for available, "away", "busy" and "dnd" for do not disturb.
note
A free text entered by the user giving additional information about the presence.