NAV Navbar
Logo ring 512
javascript

Introduction

Sopher is a web development platform that allows you to develop end-to-end encrypted web applications.

At the same time the service Sopher is a communication platform for teams, client-side identity provider and authorization framework. This documentation explains how to use the Sopher Javascript API to work with a user’s identity, data, and services.

Sopher uses oAuth2 to implement authorization. The identity services are compatible with OpenID Connect to simplify user authentication.

Interactive documentation

This API documentation includes interactive elements to work with the API and real data.

For this documentation we use identities hosted at https://test.sopher.io. You can manage the documentation accounts here: Docs Account Management

Getting Started

Get the Sopher SDK via bower or npm

bower install sopherio-websdk --save (not yet) npm install @sopherio/websdk --save (not yet)

or link or download from CDN

https://id.sopher.io/v1/sopher.js

If you want to make sure we do not change the SDK source code from under you feet you find corresponding subresource integrity hashes in this file:

https://id.sopher.io/v1/sri.json

Usage

include the Sopher SDK via script tag or via RequireJS

<script
  src="lib/sopher.js"
  integrity="sha384-<SRI-hash-sha384>"
></script>
// configure requirejs
require.config({
  paths: {
    sopher: '//id.sopher.io/v1/sopher.js'
  }
});
// include the Sopher SDK as AMD module
require(['sopher'], (sopher) => {
  sopher.init(<APP_ID_TOKEN>)
  .then(() => {
    // use the SDK
  })
  .catch(error => {
    // perform error handling
  })
})

You can include Sopher SDK via script tag or as UMD module.

Use of Promises

Using promises

sopher.init(<APP_ID_TOKEN>)
.then(() => sopher.getConnectedUser())
.then(userId => sopher.getUserDetails(userId))
.then(userInfo => {
  // write user info to ui
})
.catch(error => {
  // perform error handling
})

The Sopher SDK uses native promises to respond asynchronously. Every method returns a native Promise even if the call returns synchronously. We have decided to do so to not mix the style of javascript between the calls.

In addition to this you can chain all Sopher SDK calls using promise chaining.

Initialization

Register an app to obtain an app id token

{
  "name": "Sopher API Documentation",
  "id": "07c6dda9-bf56-4a1f-b199-5d2c63e36b74",
  "origin": "https://doc.sopher.io",
  "email": "contact@sopher.io",
  "scopes": ["https://sopher.io/social", "https://sopher.io/userdata"],
  "logo": "https://doc.sopher.io/images/volume_256.png"
}

Sopher uses JWT app tokens to authenticate your client and allow access to the account API. You can register a new Sopher app at our developer portal.

Your id token is a JWT signed by sopher.io. It is bound to the registered origin. It contains information about the scopes of your application, your contact email, and application icon.

We recommend to register test client ids for, e.g., localhost, 127.0.0.1:8080, or *.dev origins. We sign ids on these origins without any restrictions on scopes or services.

sopher.init

// init sopher with your app id token
sopher.init('<APP_ID_TOKEN>')
.then(() => {
  // do stuff with sopher accounts
})
.catch(error => {
  // error handling
});

The Sopher SDK has to be initialized with the app id token before any function can be used:

sopher.init(<APP_ID_TOKEN>): Promise

returns a Promise that resolves when the SDK has been successfully initialized. The Sopher SDK injects an iFrame into the page that handles the communication with the user’s account.

There are three optional arguments to sopher.init()

sopher.init(<APP_ID_TOKEN>, {coreHost, accountHost, namespace} = {}): Promise

coreHost defines the host where the Sopher core application is hosted. At the same time it defines the origin for user account data within the storage of the browser. Defaults to https://id.sopher.io/v1.

accountHost hosts the account management and authorization application, defaults to https://account.sopher.io.

namespace is a string that is prefixed to the database names of user data. Defaults to the empty string.

For the interactive examples of this documentation we use https://test.sopher.io/v1 as core host and APIDOC as namespace. You can check the contents of the user databases in the developer tools of your browser or access the manage the test accounts by appending these options to the accountHost: Docs Account Management. These options are for testing purposes only, in a production environment you must leave them out.

sopher.dispose

// dispose the Sopher SDK
sopher.dispose()
.then(() => {
  // shutdown complete
})
.catch(error => {
  // an error occurred
});

sopher.dispose(): Promise

Removes the SDK from the page. In particular the core iframe is removed and any background activity is stopped.

This method should be used in a unit-testing environment as a part of the tear-down phase of a test.

sopher.reset

sopher.reset(): Promise

Resets the SDK. Any user information is deleted, the connected user is disconnected.


sopher.reload

sopher.reload(): Promise

Loads the internal SDK state from local storage and session storage.

sopher.getVersion

// obtain the Sopher core version
sopher.getVersion()
.then(version => {
  // do something with version
});

sopher.getVersion(): Promise

Returns a Promise with the version number of the Sopher core that is connected to the page.

sopher.setInitTimeout

sopher.setInitTimeout(timeout)

Sets the timeout in milliseconds to be used in sopher.init() calls. It is the time that we wait for the sopher core to get loaded and respond.

sopher.setApiTimeout

sopher.setApiTimeout(timeout)

Sets the timeout for API calls, e.g., sopher.social.getContacts().

Authorization

All methods in this section are contained in the namespace sopher.auth. It allows an app to connect to its users and manage authorization and session information.

sopher.auth.connect

sopher.auth.connect()
.then(userId => {
  // the user with the id userId is connected
})
.catch(error => {
  // perform error handling
});

Returns the base64 encoded user id of the connected user, e.g.:

'Vfh1bEUSl6pkfarfPu9pFMoiGzlUV8LnbKatm6zTp_U'

sopher.auth.connect(): Promise

The function sopher.auth.connect() connects a user to the app. It returns a Promise that resolves with the userid of the connected user or rejects with an error if the user cancels the authorization process.

On connection two tokens are issued and stored by the SDK: An authorization token authToken and a sessionToken. The authToken is stored in localStorage, the sessionToken is stored in sessionStorage. Both tokens are managed my the SDK. It uses the authToken to refresh the sessionToken. The sessionToken is used to issue authorized API calls.

sopher.auth.connect(userId): Promise

connects the user with id userid and obtains a session. The previous connected user is disconnected.


result

sopher.auth.disconnect

sopher.auth.disconnect(): Promise

Disconnects the connected user from the app. Subsequent calls to the user related API will fail as there is no active session.


sopher.auth.getConnectedUser

sopher.auth.getConnectedUser(): Promise

Returns a Promise that resolves with the connected user’s id. If no user is connected null is returned.


result

sopher.auth.getUserIds

sopher.auth.getUserIds()
.then(userIds => {
  // obtain known user ids
})
.catch(error => {
  // perform error handling
});

Returns an array of app user ids

[
  "BrcvcBoj3gfQAp8Sk8TlopJrYHXLjzXgV7_h-L4NqUo",
  "YyVp4w3nvLagc4RUXTrgJ7ocqkeJUXi7i5023ENJYYo",
  "nGUdp3T3IafOLy0Z6-GCn2XSiTAE479Mgp-JMkTQqlM",
  "wtpej7VdHVMfmEnXY34xTyOEO9OnVtxNPGZlx_Rt9RM"
]

sopher.auth.getUserIds(): Promise

Returns an array with the ids of the users of this app.


result

sopher.auth.removeUser

sopher.auth.removeUser(userId): Promise

removes a user from the app. Discards previously obtained authorization of the user with is userId. A user can reauthorize the application to connect again.


sopher.auth.isAuthorizationValid

sopher.auth.isAuthorizationValid(userId): Promise

returns a native Promise that resolves with true or false if there is a valid authorization for the given userId. A user can revoke an authorization, use this method to check if a previously granted authorization is still valid.


result

sopher.auth.validateUsers

sopher.auth.validateUsers(): Promise

validates the authorization of all users and removes the users from the application that revoked the authorization.


result

sopher.auth.getUser

sopher.auth.getUser(userId)
.then(user => {
  // render user details
})
.catch(error => {
  // perform error handing
});

The user details contain the display name, username, and avatar image of the user

{
  "id": "wtpej7VdHVMfmEnXY34xTyOEO9OnVtxNPGZlx_Rt9RM",
  "name": "Docu Test User",
  "username": "docu1",
  "avatar": "data:image/png;base64,iVBORw0..."
}

sopher.auth.getUser(userId): Promise

Obtains information about a connected user with user id userId. This information is not protected by a scope or authorized session. This is intended to be used to render a list of all application users independent of active sessions.


result

sopher.auth.getAuthorization

sopher.auth.getAuthorization(userId)
.then(auth =>) {
  // show authorization
})
.catch(error => {
  // perform error handling
});

Returns the the user’s authorization information

{
  "scopes_granted": [
    "https://sopher.io/social",
    "https://sopher.io/userdata"
  ],
  "origin": "https://doc.sopher.io",
  "publicKey": {
    "alg": "RS256",
    "e": "AQAB",
    "ext": true,
    "key_ops": [
      "verify"
    ],
    "kty": "RSA",
    "n": "1EOKeHMasJBx2iY3yfwW3NkWmJeEf9u1XIBr2-7QrlzXtNJiEtfbb3a3CKtFGAD0cfSqcR_j3f-Cc0oAgo02rnkXhu_GbLgVdzA5NeWWex9b4yFODFDlTaBagkY1MsU3Nr7ITGqOaHTd7WswE8R4hcl5xO9HyrPXdPtap4L1MPzMUgyVsOjo0DnlgRRl7C3PtPKCn4FH5Sy8v_e83cM7I4ZR6zTN_XxTWMGXdR5v69b54TFYCktuT99y0Xqcb07M51AEHiDCiCDmvrCPqWaqC__wZO5Az0yMwOH5RbvznAQMeJP28inOIdKpEqNUO1ylpt9imd46hdx5lOk9S4smXw"
  },
  "appuser": "Dg3DqSw9Mf9UF35bFTdG-gdHQNlMTgW-kyn0cXeVdBY"
}

sopher.auth.getAuthorization(userId): Promise

returns the decoded information of the user’s authorization token. Authorization tokens are JWT style tokens that contain information about the user’s relation to the app.


result

sopher.auth.addAuthorizationToken

sopher.auth.addAuthorizationToken(token): Promise

adds an authorization token to the app. This corresponds to adding a new user to the app.

sopher.auth.getAuthorizationToken

sopher.auth.getAuthorizationToken(userId): Promise

returns a Promise that resolves with the user’s authorization token. Use sopher.auth.getAuthorization to get a decoded version of the token.


result

You might want to work with JWTs in more detail. Check out the JWT debugger at jwt.io.

User

Functions in this section are contained in the namespace sopher.user. To access this part of the API the client needs to be registered and authorized for the https://sopher.io/userdata scope.

sopher.user.getUser

sopher.user.getUser()
.then(user => {
  // use user data
})
.catch (error => {
  // error handling
});

Returns details for the connected user:

{
  "SID": "a35a5766737d93688bce6c0149add079e9a348b5aca9eee6ff79af0bb2548972",
  "name": "Frank Sinatra",
  "username": "frank",
  "email": "frank.sinatra@gmail.com",
  "avatar": "data:image/jpeg,base64,<image data>"
}

sopher.user.getUser() : Promise

This function returns user details for the connected user.


result

Social

The social API is contained in the namespace sopher.social. An application that wants to use this API needs to be registered and authorized for the https://sopher.io/social scope.

sopher.social.getIdentityToken

sopher.social.getIdentityToken()
.then(token => {
  // assemble a public link
})
.catch(error => {
  // error handling
});

Returns the identity token of the connected user. The identity token is used to identify a user and send invitations.

An application that uses social interactions should implement a user handshake via identity tokens.


result

sopher.social.loadIdentityProfile

sopher.social.loadIdentityProfile(identityToken)

Loads the identity profile for an identity given by an identity token.


result

sopher.social.inviteContact

sopher.social.inviteContact(identityToken)

Invite a contact with its identity token.


result

sopher.social.getContact

sopher.social.getContact(SID)

Get the contact with SID

{
  "SID": "7c7e93b63243187378f44b6dc341897738ead2a8b681e7a85d87398c9927215a",
  "name": "Test Contact",
  "username": "test42@test.com",
  "email": "test42@test.com",
  "avatar": "data:image/png;base64,..."
}


result

sopher.social.getContacts

sopher.social.getContacts()

Get all contacts of the connected user


result

sopher.social.deleteContact

sopher.social.deleteContact(SID)

Removes a contact with id SID from the user’s account. Revoke all contact permissions.


sopher.social.getMessages

[
  {
    "senderSID": "7c7e93b63243187378f44b6dc341897738ead2a8b681e7a85d87398c9927215a",
    "receiverSID": "a35a5766737d93688bce6c0149add079e9a348b5aca9eee6ff79af0bb2548972",
    "subject": "CHAT",
    "status": "PROCESSED",
    "timestamp": 1462485019169,
    "body": "Hi, how are you?"
  },
  {
    "senderSID": "a35a5766737d93688bce6c0149add079e9a348b5aca9eee6ff79af0bb2548972",
    "receiverSID": "7c7e93b63243187378f44b6dc341897738ead2a8b681e7a85d87398c9927215a",
    "subject": "CHAT",
    "status": "PROCESSED",
    "timestamp": 1462485036344,
    "body": "I'm fine, thanks!"
  }
]

sopher.social.getMessages(SID)

Get all messages related to the contact with id SID.


result

sopher.social.sendTextMessage

sopher.social.sendTextMessage(
  '978b161bc59a7a8100831a69baaef150fe63a35b6e198b35d102dfacb09e83a0',
  'Hallo 😀'
)
.error(error => {
  // error handling
})

sopher.social.sendTextMessage(receiverSID, text)

{
  "id": "118aa93b-7e5a-4a14-a0db-6112ccdced0a",
  "senderSID": "61f9b85e75add93a33c9beecde398b7ce5f2b52647b1877eb930375b7182c269",
  "receiverSID": "978b161bc59a7a8100831a69baaef150fe63a35b6e198b35d102dfacb09e83a0",
  "status": "NEW",
  "timestamp": 1576742841335,
  "subject": "CHAT",
  "body": "Hallo 😀"
}

Send a message to a contact.

Parameters

message a message object:


result

Persistence

User data persistence, coming soon…

APIs

3rd-party APIs via sopher SDK, coming soon…

OAuth Authorization

Sopher accounts can act as Self-Issued OpenID Connect provider: “OpenID Connect is a simple identity layer on top of the OAuth 2.0 protocol. It enables Clients to verify the identity of the End-User based on the authentication performed by an Authorization Server, as well as to obtain basic profile information about the End-User in an interoperable and REST-like manner.”

Sopher implements the OpenID Connect Protocol on top of the Implicit Flow of the OAuth 2.0 specification [1, 2]. A sopher account acts as a Self-Issued Identity Provider [3].

Authorization Request

The sopher OAuth 2.0 authorization end point can be accessed at

https://account.sopher.io#auth

Parameters

https://account.sopher.io#auth?  
client_id=http://clientorigin.com/auth&  
registration=<JSON with client_id_token>&    
response_type=id_token&  
scope=openid&  
...

Parameters are appended to this end point URI as part of the fragment of the URL, e.g.,

the registration parameter JSON object

{
  "client_id_token": "eyJhbGciOiJSUzI1NiI..."
}
parameter value
response_type, OAuth 2.0 Response Type value that determines the authorization processing flow to be used. Sopher only accepts the value id_token.
client_id Sopher uses the Sefl-Issued Implicit OpenID Connect flow. Following the specs the client_id contains the redirect URI of the client [3].
registration An url encoded JSON object with the attribute client_id_token containing the client ID obtained via registration at http://dev.sopher.io. This parameter must be present in order to authenticate your client and pass information such a the name and client logo of your application.
scope A list of space-delimited, case-sensitive strings of scope Parameters [4]. Currently only the openid scope is supported.
nonce String value used to associate a Client session with an id_token, and to mitigate replay attacks. The value is passed through unmodified from the Authentication Request to the id_token. Sufficient entropy must be present in the nonce values used to prevent attackers from guessing values.
state Opaque value used to maintain state between the request and the callback. Typically, Cross-Site Request Forgery (CSRF, XSRF) mitigation is done by cryptographically binding the value of this parameter with a browser cookie. This value is round tripped to the Authorization Response as an url parameter.
prompt Optional, currently only select_account is supported which is the default.

[1] OpenID Connect Core 1.0 - Authentication using the Implicit Flow
[2] The OAuth 2.0 Authorization Framework - Implicit Grant
[3] OpenID Connect Core 1.0 - Self-Issued OpenID Provider
[4] OpenID Connect Core 1.0 - Requesting Claims using Scope Values

Authorization Response

On successful authentication and consent by the user sopher redirects the browser to the URI contained in the client_id parameter. The id_token and further parameters are contained in the fragment component of the URI.

Parameters

parameter value
id_token The ID Token is a security token that contains Claims about the Authentication of an End-User by an Authorization Server when using a Client, and potentially other requested Claims. The ID Token is represented as a JSON Web Token (JWT)
state OAuth 2.0 state value. Must be verified.

The id_token is a JSON Web Token (JWT) containing user information. In particular the attributes used by sopher are

{
  "iss": "https://self-issued.me",
  "sub": "lmGlAlIG8v-ip47K5sfBrFAXlKdOEBFVQs-VjEEJtkg",
  "sub_jwk": {
    "alg": "RS256",
    "e": "AQAB",
    "ext": true,
    "key_ops": [
      "verify"
    ],
    "kty": "RSA",
    "n": "yv1ikO-rbN5Vsb-AFdaDvs0IXyuYIiN4HE4N14iXjpY..."
  },
  "aud": "https://test.sopher.dev/oauth",
  "exp": 1468432119,
  "iat": 1468431819,
  "auth_time": 1468431819,
  "nonce": "my nonce"
}
attribute value
iss Is equal to https://self-issued.me
sub The appuser id. This value is the thumbprint of the public key sub_jwk.
sub_jwk Public key used to sign this id_token.
aud Is equal to the redirect_uri of the request (The value passed via the client_id parameter).
exp Expiration date in seconds from 1970
iat “Issued at” timestamp.
auth_time The timestamp of the first authorization for this audience.
nonce The nonce passed in the request

Validation of the response

The validation of the id_token obtained in the response is performed along the lines described in the OpenID Connect specification for the Self-Issued Identity Provider case.

It basically amounts to verifying the id_token signed JWT and checking the thumbprint of the public key against the sub claim of the response.