Lolo Authentication

Lolo's Authentication

The Lolo API Auth Library Function demonstrates how easy it is to add authentication to a HTTP or Websocket handler.

The Lolo API Auth function, when connected to the Websocket or HTTP trigger, checks if the credentials in the request (JWT or API key) matches a Lolo user. If successful and the API Key or JWT token does match a Lolo user, the library function adds a session object to the event with information about the user (primaryAccountId, email, role & accountId). This allows you to add authorization on your own based on the data you receive from the session object.

To create API keys please navigate to the Admin section of your Lolo Account. The API key is a token to access user account information from the API key's owner.

Lolo's Authentication with an HTTP handler

If you are not familiar with the HTTP trigger please go through the Hello World demo quickly before.

To use the Lolo API Auth with an HTTP Trigger simply attach it to the trigger node. The library function does not need to be configured but if the "authorize" checkbox is checked then it rejects POST, PUT and DELETE requests if the user's key is set to readonly.

When the Lolo API Auth is attached to the HTTP trigger, the Lolo API Auth function will not authorize any requests without a valid Lolo API Key in the header. See how to structure this below for your HTTP requests.

const options = {
   ...
    headers: {
      ...,
      'Lolo-Api-Key': "your key here",
      ...
    },
    ...
  }

To get a Lolo API Key go to the Admin section of your Lolo account and create a new one from there.

This key will authorize any Lolo user and give you data in the event object on which Lolo user the API key belongs to. To access this data you only have to extract primaryAccountId, email, role & accountId from the ev.session object.

exports.handler = async(ev, ctx) => {
  const { route, log } = ctx;  
  { primaryAccountId, email, role, accountId } = ev.session;

  // Log user information
  log.info("user email accessing the endpoint: ", email);

};

See a quick one minute demo on how to use an HTTP trigger with Authentication below. Here we are only sending back a response to the GET request with information on the user (email) of whom the API key belongs to.

If you want to be sure that only specific Lolo users can access this endpoint, you can set up your own custom authorize function as you now have information about the user that is trying to access your API.

Lolo's Authentication with a Websocket Handler

As you do with the HTTP handler connect the Lolo API Auth function with the Websocket Trigger to authenticate the connection. The Websocket trigger though is a bit more complicated to work with than the HTTP trigger. We need to add the Lolo API Auth before we process the request. Please take a look at our full Websocket Application demo here first.

If you want to give this a go right away, see our full demo for a Websocket with authentication below.

This video is showing how to authenticate that the user is a Lolo User. It will give you a session object to whom the Lolo API key belongs to. From here, you can authorize users based on the user data that you receive. In the demo we are grabbing the user email from the ev.session to demonstrate how this works.

We are copying and pasting the code to develop faster here. See the code and the explanation on what it does below to do the same.

const connections = {};

exports.handler = async (ev, ctx) => {
  const { route, input, inputs, log, emit } = ctx;
  const { sessionId } = ev;

  // check incoming port (i.e. req, message or close)
  switch (input) {

    // on first connection
    case inputs.req:
      connections[sessionId] = {
        send: body => emit('response', { body }),
        end: () => emit('response', { end: true }),
        info: ev.headers,
        username: ev.session.email // user email address provided by Lolo API Auth
      }
      ev.body = { connected: true, yourConnectionId: sessionId };
      // re-route data to 'req' output port
      route(ev, 'req');
      break;

    // on subsequent messages 
    case inputs.msg:
      // re-route data to 'msg' output port
      route({ connections, message: ev.message, sessionId }, 'msg')
      break;

    // when client disconnects 
    case inputs.close:
      log.info("client has disconnected");
      delete connections[sessionId];
      break;
  }
};

The code in the Process Request node is checking whether this is a first connection and if so saving the user to the connections object. The Websocket trigger is taking advantage of Lolo's baked in state store here to save the connections. On subsequent connections the code is routing the message to the msg port to be further processed. If the connection is closed, it will delete the connection from the connections object.

exports.handler = async(ev, ctx) => {
  const { emit, log } = ctx;
  // Log to the console that a client has connected
  log.info("client has connected");
  // send response to the client
  emit('response', ev);
};

The code in the Affirm Connection node is merely sending back a response if the connection has been established. The Websocket trigger has a once() listener registered and is waiting for an emit() response to successfully establish a connection.

Once and emit is an event-local pub / sub mechanism that allows communication between functions on the same event-path using signals. That is, you can set up a once() method to register a listener that will be triggered when the emit() method is used within the Application. So, the Websocket trigger won't connect until we send the emit() response back. If you want to read about once() and emit() to use it in your own applications please see documentation here.

exports.handler = async (ev, ctx) => {
  // extract connections, and current session id from the event data
  const { connections, sessionId } = ev;
  // send messages
  await broadcastToAll(ctx, connections, sessionId, ev);
};

const broadcastToAll = async ({ log }, connections, currentSessionId, ev) => {

  // loop through connections
  Object.keys(connections).forEach(sessionId => {
    try {
        // send message to everyone but the current sessionId
        if (currentSessionId !== sessionId) {
        const { username } = connections[sessionId];
        connections[sessionId].send(`${ username } says: ${ev.message}`) // use provided email
        } 
    } catch (e) {
      log.error(e)
    }
  })
};

When the connection has been established the Websocket trigger will process all messages in the msg port which will be routed to the Send Messages node. This code above will process all messages and send back a message to all users that are not the current user. This is because we are creating a mock chat application. We do not want to see our own messages sent back, only that of other users.

Remember to save and run your application and wait for a 4000 response in the Logs before trying to connect. Also remember to connect to the socket with single quotes around the url when you are using query parameters. See example below.

wscat -c 'wss://eu-1.lolo.co/:appId/socket?lolo-api-key=<user-api-key>'

If you want to understand how to work with the Websocket trigger step by step in more detail remember to go the Websocket guide here.

Creating a New API Key

As noted, when you use the Lolo API Auth library function you will need an API key token. To create a new API Key please navigate to the Admin section of your account. Here there is a tab for API Keys where you can create as many API keys as you want. When created, the account it will be set for is the primary account you have signed in as.