dataBridges client library trust token implementation
dataBridges client library exposes a property where you can define trust token creation function before connecting to dataBridges network.
access_token:
Application can define callback function for trust token creation using dbridge.access_token
This function is called every time whenever a subscription to channel or connection to RPC server happens. After receiving the token in prescribed format token is sent with the request to DBR and validated for authenticity.
Functions can be defined either inside the property callback function or anywhere in the scope of application. Below code exhibits both ways of exposing the function.
#// Access token creation function, make sure the return JSON is of defined structure and is stringified before returned.
async def Get_access_token(channelName, sessionId, action, response):
try:
#// called external function getAccessTokenRPC for creation of access token
expect Exception as e:
print("exception: ", e)
dbridge.access_token(Get_access_token)
Action<object , object , object, object> iaccess_token;
// Access token creation function, make sure the return JSON is of defined structure and is stringified before returned.
dbridge.access_token(iaccess_token = async (object channelname , object sessionid , object action , object response) => {
// called external function getAccessTokenRPC for creation of access token
});
// Access token creation function, make sure the return JSON is of defined structure and is stringified before returned.
dbridge.access_token(new privateHandler() {
@Override
public void onPrivate(String channelName, String sessionid, String action, Object response) {
// called external function getAccessTokenRPC for creation of access token
}
});
// Access token creation function, make sure the return JSON is of defined structure and is stringified before returned.
dbridge.access_token( { (_ channelname : Any , _ sessionid : Any , _ action: Any , _ response: Any ) in
// called external function getAccessTokenRPC for creation of access token
})
Below are parameters of the callback function. These parameters are passed from library itself when executing this function.
Parameter | Description |
---|---|
channelName | (string) Channel Name for Subscription or RPC Server name in case of RPC Connection. |
sessionId | (string) Session id of the member who has requested to execute the function. |
action | (string) Defines what is the action performed during this operation. |
response | (object) Response object having properties and function to return execution results of the function back to caller. |
response: (object)
{
statuscode: 0, // 0 = Success , 1 = Failed
error_message: "", // Message if any e.g. Unauthrorized
accesskey: 'JWT Token'
}
Key | Description |
---|---|
statuscode | (int) Status code to inform the library if the generation of trust token is success of failure. Note 0 = Success and 1 = Failure. |
error_message | (string) Error message if to be passed back to library. |
accesskey | (string) JWT Token in string format |
Conn_Info: (object)
Payload for creating JWT token at Server side expects conn_info
object in case of Presence
and System
channel. This is required to store identity of the client and additional information if application wants to pass. This information is available to the callee on each received events and RPC function call.
Below is the mandatory structure to be followed while creating conn_info object.
Key | Description |
---|---|
sysid | (string) Identifier which you want your client application to be identified as |
sysinfo | (object) Application can add other client application information as per required by receiver application for security and other purposes. |
To make it simple to implement, below is the code samples for getting the access token using REST Call and dataBridges RPC Call.
Get trust token using Rest Call
In this example trust token creation is done via REST call. You will have to run REST server to serve this request. You need to replace <YOUR REST URL>
with your server rest URL and <clientIdentity>
with the Identifier which you want your client application to be identified as.
const fetch = require("node-fetch");
// Access token creation function, make sure the return JSON is of defined structure and is stringified before returned.
dbridge.access_token(async (channelName, sessionId, action, response) => {
const retVal = await fetch('<YOUR REST URL>', {
method: 'POST',
mode: 'cors', // no-cors, *cors, same-origin
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify( { channelname:channelName,
sessionid:sessionId,
action:action,
conn_info: {sysid: '<clientIdentity>',sysinfo: {}}
})
});
if (response.status != 200) {
response.end(JSON.stringify({
statuscode: 1,
error_message: "Failed",
accesskey: ''
}));
} else {
let jdata = await response.json();
response.end(jdata);
}
});
// Access token creation function, make sure the return JSON is of defined structure and is stringified before returned.
dbridge.access_token(async (channelName, sessionId, action, response) => {
const retVal = await fetch('<YOUR REST URL>', {
method: 'POST',
mode: 'cors', // no-cors, *cors, same-origin
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify( { channelname:channelName,
sessionid:sessionId,
action:action,
conn_info: {sysid: '<clientIdentity>',sysinfo: {}}
})
});
response.end(retVal.json());
});
# Access token creation function, make sure the return JSON is of defined structure and is stringified before returned.
async def Get_Access_Token(channelName, sessionId, action, response):
try:
iheadres = {"Content-Type": "application/json"}
async with aiohttp.ClientSession(connector=aiohttp.TCPConnector(verify_ssl=False)) as session:
r = await session.post('<YOUR REST URL>', data=json.dumps({"channelname":channelName,"sessionid":sessionId,"action":action,"conn_info": {"sysid": "<clientIdentity>","sysinfo": {}}}), headers=iheadres)
if r.status == 200:
rdata = await r.text()
response.end(rdata)
else:
response.end(json.dumps( {"statuscode": 1, "error_message": "failed", "accesskey": ""}))
except Exception as e:
print("exception:" , e)
response.end(json.dumps( {"statuscode": 1, "error_message": "failed", "accesskey": ""}))
dbridge.access_token(Get_Access_Token)
// Access token creation function, make sure the return JSON is of defined structure and is stringified before returned.
Action<object , object , object, object> iaccess_token;
dbridge.access_token(iaccess_token = async (object channelname , object sessionid , object action , object response) => {
string new_channelname = channelname as string;
string new_sessionid = sessionid as string;
string new_action = actionas string;
CprivateResponse rsp = response as CprivateResponse;
try{
Dictionary<string , object> access_info = new Dictionary<string , object>() { {"ch" , new_channelname}, {"sid", new_sessionid}, {"act" , new_action} ,{"conn_info" , new Dictionary<string,string>() { {"sysid", "<clientIdentity>" ,"sysinfo", ""} } }};
string access_info = new JavaScriptSerializer().Serialize(access_info);
var stringContent = new StringContent(access_info , UnicodeEncoding.UTF8 , "application/json")
using(var client = new HttpClient()){
var result = await client.PostAsync(new Uri("<YOUR REST URL>") , stringContent)
if(result.IsSuccessStatusCode){
rsp.end(await rsp.Content.ReadAsStringAsync());
}else{
rsp.end("<Failed Response>")
}
}
}catch(Exception e){
console.Writeline("Exception: {0}" , e);
}
});
// Access token creation function, make sure the return JSON is of defined structure and is stringified before returned.
dbridge.access_token(new privateHandler() {
@Override
public void onPrivate(String channelname, String sessionid, String action, Object response) {
cresponse responseHandler = (cresponse) response;
try{
OkHttpClient client = new OkHttpClient();
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
JSONObject access_json = new JSONObject();
JSONObject client_json = new JSONObject();
JSONObject sys_info = new JSONObject();
try{
access_json.put("channelname" ,channelname );
access_json.put("sessionid" ,sessionid );
access_json.put("action" ,action );
client_json.put("sysid" , "<clientIdentity>" );
client_json.put("sys_info" , sys_info );
access_json.put("conn_info" ,client_json );
}catch(Exception e){
Log.d("Exception:" , e.getMessage())
}
RequestBody body = RequestBody.create(JSON, access_json.toString());
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
Response result = client.newCall(request).execute();
if (result.code() == 200) {
responseHandler.end(response.body().string());
}else{
JSONObject access_response = new JSONObject();
try{
access_response.put("statuscode" ,1 );
access_response.put("error_message" ,"failed" );
access_response.put("accesskey" ,"" );
}catch(Exception e){
Log.d("Exception:" , e.getMessage())
}
responseHandler.end(access_response.toString());
}
}catch(Exception e){
Log.d("Exception:" , e.getMessage())
}
}
});
// Access token creation function, make sure the return JSON is of defined structure and is stringified before returned.
func convertToDictionary(text: String) -> [String: Any]? {
if let data = text.data(using: .utf8) {
do {
return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
} catch {
print(error.localizedDescription)
}
}
return nil
}
try? self.dbridge.access_token({(_ channelname:String, _ sessionid:String, _ action:String,_ response:Any) in
let rresponse:AccessResponse = response as! AccessResponse
var theJSONText:String = ""
let iparam = ["sysid": "<clientIdentity>"]
iparam["sys_info"] = ""
let param : [String:Any] = ["ch": channelname , "sid": sessionid, "act": action, "clinfo": iparam]
if let theJSONData = try? JSONSerialization.data(
withJSONObject: param,
options: .prettyPrinted
){
theJSONText = String(data: theJSONData,
encoding: .utf8)!
}
guard let serviceUrl = URL(string: url) else { return m_apiresponce}
var request = URLRequest(url: serviceUrl)
request.httpMethod = "POST"
request.httpBody = Data(theJSONText)
let session = URLSession.shared
let sem = DispatchSemaphore.init(value: 0)
let task = session.dataTask(with: request) { data, response, error in
defer { sem.signal() }
if let error = error {
rresponse.exception("error in rpcserver")
return
}
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode)
else {
let htr = response! as? HTTPURLResponse
rresponse.exception(String(htr!.statusCode))
return
}
guard let responseData = data else {
response.exception(String(htr!.statusCode))
return
}
do {
if let jsonResponse = try JSONSerialization.jsonObject(with: responseData, options: .mutableContainers) as? [String: Any] {
let assessinfo:AccessInfo = AccessInfo(jsonResponse?["statuscode"] as! Int , jsonResponse?["error_message"] as! String , jsonResponse?["accesskey"] as! String )
rresponse.end(assessinfo)
} else {
throw URLError(.badServerResponse)
}
} catch _ {
}
}
task.resume()
sem.wait()
});
try? self.dbridge.connectionstate?.bind("connected", { (event: Any) in
print("connected: \(String(describing: self.dbridge.sessionid))")
});
Get trust token using dataBridges RPC call.
In this example trust token creation is done via RPC call to RPC server. You will have to run dataBridges RPC server to receive this call and serve the JWT trust token.
// Access token creation function, make sure the return JSON is of defined structure and is stringified before returned.
dbridge.access_token(async (channelName, sessionId, action, response) => {
// Create input parameter for RPC call.
const jsonParam = {
ch: channelName,
sid: sessionId,
act: action,
conn_info: {}
};
// Only in case of presence or system connection info needs to be added into the payload.
if (channelName.indexOf("prs:") == 0 || channelName.indexOf("sys:") == 0) {
jsonParam.conn_info = {
sysid: 'clientIdentity',
sysinfo: {}
};
}
// Call RPC function by passing required parameter.
authclient.call("gettokenJson", JSON.stringify(jsonParam), 1000 * 60 * 2, null)
.then((response) => {
// send back the response to the callee function.
console.log(response)
response.end(accessResponse);
})
.catch((err) => {
// catch error and send back failure to callee function.
response.end({
statuscode: 1,
error_message: err.message,
accesskey: ''
});
console.log("AccessToken RPC Response", err.source, err.code, err.message);
});
});
//Bind to connected event, Once the dbridge is connected successfully, Subscription and other activities can be performed.
dbridge.connectionstate.bind("connected", () => {
// Connect to accessToken rpcServer
try {
authclient = dbridge.rpc.connect("accessTokenServer");
} catch (err) {
// Catch connect excpetion
console.log('dBridge rpc.connect exception', err.source, err.code, err.message)
}
// Bind to event server.connect.success, This will be triggered when the connection to authentication server is successfull
authclient.bind("dbridges:server.connect.success", () => {
// Your application code here..
});
// Bind to server.connect.fail. This will be triggered either if connection to rpcServer fails or reconnect fails.
authclient.bind("dbridges:server.connect.fail", (payload, metadata) => {
console.log('dbridges:server.connect.fail', payload.source, payload.code, payload.message);
});
});
// Access token creation function, make sure the return JSON is of defined structure and is stringified before returned.
dbridge.access_token(async (channelName, sessionId, action, response) => {
// Create input parameter for RPC call.
const jsonParam = {
ch: channelName,
sid: sessionId,
act: action,
conn_info: {}
};
// Only in case of presence or system connection info needs to be added into the payload.
if (channelName.indexOf("prs:") == 0 || channelName.indexOf("sys:") == 0) {
jsonParam.conn_info = {
sysid: 'clientIdentity',
sysinfo: {}
};
}
// Call RPC function by passing required parameter.
authclient.call("gettokenJson", JSON.stringify(jsonParam), 1000 * 60 * 2, null)
.then((response) => {
// send back the response to the callee function.
console.log(response)
response.end(accessResponse);
})
.catch((err) => {
// catch error and send back failure to callee function.
response.end({
statuscode: 1,
error_message: err.message,
accesskey: ''
});
console.log("AccessToken RPC Response", err.source, err.code, err.message);
});
});
//Bind to connected event, Once the dbridge is connected successfully, Subscription and other activities can be performed.
dbridge.connectionstate.bind("connected", () => {
// Connect to accessToken rpcServer
try {
authclient = dbridge.rpc.connect("accessTokenServer");
} catch (err) {
// Catch connect excpetion
console.log('dBridge rpc.connect exception', err.source, err.code, err.message)
}
// Bind to event server.connect.success, This will be triggered when the connection to authentication server is successfull
authclient.bind("dbridges:server.connect.success", () => {
// Your application code here..
});
// Bind to server.connect.fail. This will be triggered either if connection to rpcServer fails or reconnect fails.
authclient.bind("dbridges:server.connect.fail", (payload, metadata) => {
console.log('dbridges:server.connect.fail', payload.source, payload.code, payload.message);
});
});
async def Get_Access_Token(self, channelName, sessionId, action, response):
try:
# Create input parameter for RPC call.
inparameter = json.dumps({"ch": channelName, "sid": sessionid, "act": action, "conn_info": { "sysid": "<clientIdentity>","sysinfo": {}}})
def progress(multiresponse):
print("multiple response" , multiresponse);
# Call RPC function by passing required parameter.
p = await self.rpc_access.call("gettokenJson" , inparameter, 10000, progress )
def onResult(res):
asyncio.create_task(response.end(json.loads(res)))
def onError(res):
asyncio.create_task(response.exception("1" , res.message))
p.then(onResult).catch(onError)
except Exception as e:
print("exception:" , e)
response.end(json.dumps( {"statuscode": 1, "error_message": "failed", "accesskey": ""}))
dbridge.access_token(self.Get_Access_Token)
# Bind to connected event, Once the dbridge is connected successfully, Subscription and other activities can be performed.
async def Connected(self):
self.rpc_access = await self.dbridge.rpc.connect("accessToken")
self.rpc_access.bind("dbridges:server.connect.success" , self.rpc_connect_success)
self.rpc_access.bind("dbridges:server.connect.fail" , self.rpc_connect_fail)
async def rpc_connect_success(self, payload , metadata):
print("rpc connect success:")
async def rpc_connect_fail(self, payload , metadata):
print("rpc connect fail:")
public async void rpc_progress(object response)
{
console.WriteLine("progress response");
}
// Access token creation function, make sure the return JSON is of defined structure and is stringified before returned.
Action<object, object, object,object> iAccess_Token;
dbridge.access_token(iAccess_Token = async (object channelname, object sessionid, object action, object response) =>{
CprivateResponse rsp = response as CprivateResponse;
while(this.rpc_access == null){
Task.Delay(new TimeSpan(0,0,0,0,5));
}
while(! this.rpc_access.isonline()){
Task.Delay(new TimeSpan(0,0,0,0,5));
}
Action<object> iProgress = this.rpc_progress;
Dictionary<string , object> access_info = new Dictionary<string , object>() { {"ch" , channelname}, {"sid", sessionid}, {"act" , action} ,
{"conn_info" , new Dictionary<string,string>() { {"sysid", "<clientIdentity>","sysinfo", ""} } }};
string access_string_info = new JavaScriptSerializer().Serialize(access_info);
IPromise<object> promise = await this.rpc_access.call("gettokenJson" , access_string_info , 1000*60*2 , iProgress);
promise.Then(async( result) => {
rsp.end(result);
})
.Catch(async (error) =>{
rsp.end("<Failed Response>");
});
});
//Bind to connected event, Once the dbridge is connected successfully, Subscription and other activities can be performed.
Action<object> iconnected;
dbridge.connectionstate.bind("connected" , iconnected = (object payload) => {
try{
this.rpc_access = dbridge.rpc.connect("accessToken");
Action<object, object> isuccess , ifail;
isuccess = this.rpc_success;
ifail = this.rpc_fail;
this.rpc_access.bind("dbridges:server.connect.success" , isuccess);
this.rpc_access.bind("dbridges:server.connect.fail" , ifail);
}catch(dBError err)
{
console.WriteLine("Exception: {0}" , err)
}
})
public async void rpc_success(object payload , object metadata)
{
console.WriteLine("dbridges:server.connect.success");
}
public async void rpc_fail(object payload , object metadata)
{
console.WriteLine("dbridges:server.connect.fail");
}
// Access token creation function, make sure the return JSON is of defined structure and is stringified before returned.
dbridge.access_token(new privateHandler() {
@Override
public void onPrivate(String channelname, String sessionid, String action, Object response) {
cresponse responseHandler = (cresponse) response;
try{
JSONObject access_json = new JSONObject();
JSONObject client_json = new JSONObject();
try{
access_json.put("ch" ,channelname );
access_json.put("sid" ,sessionid );
access_json.put("act" ,action );
client_json.put("sysid" , "<clientIdentity>" );
access_json.put("conn_info" ,client_json );
}catch(Exception e){
Log.d("Exception:" , e.getMessage())
}
String access_string_info = access_json.toString();
rpc_access.call("gettokenJson", access_string_info, 2000, new callResponse() {
@Override
public void onResult(String response, boolean isEnd) {
responseHandler.end(response);
}
@Override
public void onError(dBError dberror) {
response.exception("error");
}
});
}catch(Exception e){
Log.d("Exception:" , e.getMessage())
}
}
});
//Bind to connected event, Once the dbridge is connected successfully, Subscription and other activities can be performed.
dbridge.connectionstate.bind("connected", new connectionHandler() {
@Override
public void onEvent(Object message) {
try {
rpc_access = dbridge.rpc.connect("accessToken");
rpc_access.bind("dbridges:server.connect.success",new ServerEventHandler() {
@Override
public void onEvent(Object message, serverMetaData metadata) {
// do your work
}
} );
rpc_access.bind("dbridges:server.connect.fail",new ServerEventHandler() {
@Override
public void onEvent(Object message, serverMetaData metadata) {
// do your work
}
});
}catch (dBError dberror){
Log.d("Exception", dberror.code + "," + dberror.source + dberror.getMessage());
}
}
});
func convertToDictionary(text: String) -> [String: Any]? {
if let data = text.data(using: .utf8) {
do {
return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
} catch {
print(error.localizedDescription)
}
}
return nil
}
// Access token creation function, make sure the return JSON is of defined structure and is stringified before returned.
try? self.dbridge.access_token({(_ channelname:String, _ sessionid:String, _ action:String,_ response:Any) in
let rresponse:AccessResponse = response as! AccessResponse
var theJSONText:String = ""
let iparam = ["sysid": "<clientIdentity>"]
iparam["sys_info"] = ""
let param : [String:Any] = ["ch": channelname , "sid": sessionid, "act": action, "clinfo": iparam]
if let theJSONData = try? JSONSerialization.data(
withJSONObject: param,
options: .prettyPrinted
){
theJSONText = String(data: theJSONData,
encoding: .ascii)!
}
self.rpcclient?.call("gettokenJson", theJSONText, 10000, { (response: Any) in
print("inprogress response: \(response as! String)")
})
.done{ (response: Any) in
let dict = self.convertToDictionary(text: response as! String)
let assessinfo:AccessInfo = AccessInfo(dict?["statuscode"] as! Int , dict?["error_message"] as! String , dict?["accesskey"] as! String )
rresponse.end(assessinfo)
}.catch {(error:Any) in
rresponse.exception("error in rpcserver")
}
});
//Bind to connected event, Once the dbridge is connected successfully, Subscription and other activities can be performed.
try? self.dbridge.connectionstate?.bind("connected", { (event: Any) in
print("connected: \(String(describing: self.dbridge.sessionid))")
self.mlog?.sendlog("connected: \(String(describing: self.dbridge.sessionid))")
try? self.rpcclient = self.dbridge.rpc?.connect("accessToken")
try? self.rpcclient?.bind("dbridges:rpc.server.connect.success", { (event: Any , metadata: Any) in
let mtd = metadata as! ServerMetaData
print("dbridges:rpc.server.connect.success \(mtd.ToString())")
});
try? self.rpcclient?.bind("dbridges:rpc.server.connect.fail", { (event: Any , metadata: Any) in
let mtd = metadata as! ServerMetaData
print("dbridges:rpc.server.connect.fail \(mtd.ToString())")
});
try? self.rpcclient?.bind("dbridges:rpc.server.online", { (event: Any , metadata: Any) in
let mtd = metadata as! ServerMetaData
print("dbridges:rpc.server.online \(mtd.ToString())")
});
});