FD1 Client Protocol

Authentication

The first action on your websocket must be a fd1.session.login message containing details of who you are. You cannot authenticate using HTTP headers as browsers do not allow additional headers.

Authentication is about identifying who you are. Your authentication, once approved, is then used to determine what you are authorised to do Authentication and Authorisation are seperately managed, but closely intertwined.

  1. When you connect to a server, the Fieldpine server will send NOTHING until you successfully authenticate.
  2. If using a browser, websockets ARE impacted by browser mixed content rules. If your source web page is https, then you cannot connect to ws (non https version) must connect to a wss URL.
    You should be using https/wss anyway
  3. Websockets are NOT impacted by browser CORS restrictions. This is why the server insists on a authenticate before responding at all.
  4. Some servers require an HTTP Authorization header before you can connect. However you cannot set the Authorization header when using javascript "new Websocket".
    If you are opening the websocket from an environment outside the browser, set the Authentication header directly.
let TargetUrl = "wss://example.com/fd1/open_websocket";
let MyWebSocket = new WebSocket(TargetUrl);

MyWebSocket.onopen = function () {
    // Socket is open!  Can read/write data

    // But we MUST send a session login packet first
    let myDate = new Date();
    let req = {
        a: "fd1.session.login",
        v: {
            apikey: "my api key",
            tz: myDate.getTimezoneOffset(),
            localtime: myDate.getFullYear() + "-" + (myDate.getMonth() + 1)
                + "-" + myDate.getDate() + " " + myDate.getHours()
                + ":" + myDate.getMinutes() + ":" + myDate.getSeconds()
                + "." + myDate.getMilliseconds()
        }
    }

    MyWebSocket.send(JSON.stringify(req));
}

MyWebSocket.onmessage = function (event) {
    // Fired on every message received from the server.
    // Message payload is in event.data
}

// Fired when a connection with a WebSocket is closed
MyWebSocket.onclose = function (event) {

}

// Fired when a connection with a WebSocket has been closed because of an error
MyWebSocket.onerror = function (event) {
}

Authentication Methods

There are several methods of authenticating. Select which suits your environment and needs. Administrators can enable/disable methods

Apikey

ApiKey, sent in initial fd1.session.login

{
    a: "fd1.session.login",
    v: {
        apikey: "my api key",
    }
}

Token

Token, sent in initial fd1.session.login. Token authorisation is typically used to give access to a customer or supplier to access a targeted subset of data. This can be seen being used with Customer Displays, where the instore QR code includes a token that permits access to only that single sale

{
    a: "fd1.session.login",
    v: {
        token: "my token",
    }
}

Encryption Key

Encryption Key. (Beta Testing). With encryption key, you indicate to the server who you are, but do not send your password. Rather you encrypt every payload and decrypt every response. Encryption ensures that every message is secure between the client and the server. Fieldpine use cloud services and many of them are able to see clear text data, even when using a SSL/TLS connection.

{
    a: "fd1.session.login",
    v: {
        encryption_user: "your login name (email)",
    }
}

Server returns a hash value

{
    r: "fd1.session.login",
    data: {
        hash: "jdj3n59tvbcb3b56hghcbv2j4h6j5h3v5c23c$h"
    }
}
    

From then on, all requests sent from you to the server, must encrypt, using the real payload, the secret password, and the hash value returned from the server. More details are in the session endpoint documentation.

Request
{
    a: "fd1.products.get_products",
    rq: 293848
}
Encrypted

»
Transmitted
{
 enc: "Ksn294...8635h"
}

More

When connecting there are optional fields, such as geo location, that can be sent as well.

For full details of fd1.session.login, see Session Endpoint details. But the majority of use cases simply need to send the following

Example - Simple

  1. Create your webpage (HTML)
  2. Open your websocket wss://your-server.com/fd1/open_websocket
  3. The server will not reply until you authenticate
  4. Send your authentication packet
    {
      a: "fd1.session.login",
      v: {
        apikey: "your-api-key",
        ... optional additional arguments
      }
    }
    
  5. Server will reply with acknowledgement if ok. It will remain silent if the authentication is not accepted.
  6. You can now call any endpoint you are authorised too

Example - Simple, with GeoLocation

  1. Create your webpage (HTML)
  2. Using standard Javascript request users Geo Position
    var sGeo = null;
    var ServerSocket = null;
    
    // We ask for Geo co-ords if we can, as these help position what devices can be used
    if (navigator.geolocation) navigator.geolocation.getCurrentPosition(function (pos) {
        sGeo = pos.coords;
    
        if ((ServerSocket != null) && (ServerSocket.readyState == 1)) {
            // Geo details have arrived, socket is already connected, so send using session set option
            let req = {
              a: "fd1.session.set_option",
              v: {
                geo: {
                    latitude: sGeo.latitude,
                    longitude: sGeo.longitude,
                    accuracy: sGeo.accuracy,
                    altitude: sGeo.altitude,
                    altitudeAccuracy: sGeo.altitudeAccuracy
                }
              }
            }
    
            ServerSocket.send(JSON.stringify(req));
        }
    });
    
  3. Open your websocket wss://your-server.com/fd1/open_websocket
    ServerSocket = new WebSocket("wss://your-server.com/fd1/open_websocket");
    
  4. The server will reply with a hello JSON packet, but this will typically be empty until you authenticate
  5. Send your authentication packet. This is likely to be running before Geo Position returns
    let req = {
      a: "fd1.session.login",
      v: {
        apikey: "your-api-key"
      }
    }
    
    // If we already have Geo details, send it now
    if (sGeo) {
        req.v.geo = {
            latitude: sGeo.latitude,
            longitude: sGeo.longitude,
            accuracy: sGeo.accuracy,
            altitude: sGeo.altitude,
            altitudeAccuracy: sGeo.altitudeAccuracy
        }
    }
    
    ServerSocket.send(JSON.stringify(req));
    
  6. Server will reply with acknowledgement
  7. You can now call any endpoint you are authorised too