Tutorials

Client & Server Token Authentication Tutorial

Ably supports two types of authentication schemes. Basic authentication uses one of your private API keys and is the simplest scheme designed for use by your servers. Token authentication is mostly used by your device and browser clients whereby a short-lived secure token is issued to them by your servers.

Most of our other tutorials demonstrate the use of the simple basic authentication scheme. In this tutorial we are focusing on how you can use the recommended token authentication scheme for your untrusted clients.

It is important to bear in mind that when using token authentication, unlike with basic authentication, the client should not be given a token at the time it is instanced. This is because the token will expire. Instead, the client should be configured with a means to obtain a token whenever it needs to authenticate with Ably. As tokens typically expire every hour, which minimizes the impact of compromise on a client device or browser, it is necessary that the client can obtain a new token to authenticate whenever the token expires or needs refreshing.

Let’s get started and show you a typical client-server architecture using token authentication.

Step 1 – Set up a free account with Ably

In order to run these tutorials locally, you will need an Ably API key. If you are not already signed up, you should sign up now for a free Ably account. Once you have an Ably account:

  1. Log into your app dashboard
  2. Under “Your apps”, click on “Manage app” for any app you wish to use for this tutorial, or create a new one with the “Create New App” button
  3. Click on the “API Keys” tab
  4. Copy the secret “API Key” value from your Root key and store it so that you can use it later in this tutorial

    Copy API Key screenshot

Step 2 – Install Ably on your server

To start using Ably in your JRE application, you need to include the Ably Client library. We recommend that you include the latest client library via Gradle in your project’s gradle.build file.

repositories {
  jcenter()
}

dependencies {
    compile 'io.ably:ably-java:1.0.0'
}

In the above example a specific version of the library is referenced, however we recommend you check which is the latest stable version and always use that. Follow link to get the latest stable release for Java.

The server-client library must be instanced with the private API key you copied in Step 1. This will ensure that the basic authentication scheme is used, which is almost always the right choice for your own trusted servers where the risk of compromise of your API key credentials is low.

Add the following to a file named Example.java to instance the Ably library inside your Node.js server:

private final static String API_KEY = "INSERT-YOUR-API-KEY-HERE";

private AblyRest ablyRest;

public Example(){
    try {
      initAbly();
    } catch (AblyException e) {
      e.printStackTrace();
    }
}

private void initAbly() throws AblyException{
    ablyRest = new AblyRest(API_KEY);
}

See this step in Github

To start using Ably on your Node.js server, you first need to install the NPM module. The NPM module can be installed as follows:

npm install ably

The server-client library must be instanced with the private API key you copied in Step 1. This will ensure that the basic authentication scheme is used, which is almost always the right choice for your own trusted servers where the risk of compromise of your API key credentials is low.

Add the following to a file named server.js to instance the Ably library inside your Node.js server:

var Ably = require("ably");
var rest = new Ably.Rest({ key: apiKey });

To start using Ably you first need to install the Ably RubyGem. The RubyGem can be installed as follows:

gem install ably

Or if using bundler, simply add the following to your Gemfile and run bundle install:

gem 'ably'

The server client library must be instanced with the private API key you copied in Step 1. This will ensure that the basic authentication scheme is used, which is almost always the right choice for your own trusted servers where the risk of compromise of your API key credentials is low.

As you do not need asynchronous access to the realtime API for this tutorial, you’ll be using the simpler REST client library.

require 'ably'
ably = Ably::Rest.new(key: api_key)

See this step in Github

To start using Ably you first need to install The REST library for Python, it’s hosted on Github and is published on PyPI and can be installed as follows:

pip install ably

Then it can be imported and instantiated as follows:

from ably import AblyRest
client = AblyRest(api_key)

For the purpose of this tutorial, create a file called server.py containing the code above. You’ll be using this file later on.

Note on string encodings

Since Ably supports both string and binary payloads, we recommend that strings passed to the library for publishing to Ably be unicode strings (e.g. event names or payload data). This is to avoid ambiguity regarding the type of payload. In Python 3 this is the normal string type, but in Python 2 it is not, so we suggest you prefix string literals with the u prefix (eg u'eventname' – or alternatively, use from __future__ import unicode_literals, which will make this automatic), and to explicitly decode any user input (e.g. raw_input().decode(sys.stdin.encoding).

See this step in Github

To start using Ably you first need to install the composer package on packagist into your composer.

composer require ably/ably-php --update-no-dev

The server-client library must be instanced with the private API key you copied in Step 1. This will ensure that the basic authentication scheme is used, which is almost always the right choice for your own trusted servers where the risk of compromise of your API key credentials is low.

Create a directory called public, which will serve as the document root. Add the following to a file named ably.php to instance the Ably library inside your php script:

require_once __DIR__ . '/../vendor/autoload.php';
$ably = new \Ably\AblyRest("{{ApiKey}}");

See this step in Github

For this Swift example, you need a web server to generate token requests. You will be using Ruby for the server in this tutorial. To start using Ably with Ruby, you first need to install the Ably RubyGem. The RubyGem can be installed as follows:

gem install ably

Or if using bundler, simply add the following to your Gemfile and run bundle install:

gem 'ably'

The server-client library must be instanced with the private API key you copied in Step 1. This will ensure that the basic authentication scheme is used, which is almost always the right choice for your own trusted servers where the risk of compromise of your API key credentials is low.

As you do not need asynchronous access to the realtime API for this tutorial, you’ll be using the simpler REST client library.

require 'ably'
ably = Ably::Rest.new(key: api_key)

See this step in Github

Step 3 – Set up your web server

Before a client connects to Ably, it will check if it has suitable credentials to authenticate with Ably. As you’ll be using the recommended token authentication scheme in the client for this demo, when the client starts up and attempts to connect to Ably, it will request a token immediately so that it can then authenticate with Ably.

As tokens are typically issued from your own web servers, you’ll set up a simple web server now for this tutorial.

Spring Boot is a very popular and simple web framework for Java. You’ll need to get this set up:

First you’ll add following configuration to the build.gradle file:

buildscript {
  repositories {
      mavenCentral()
  }
  dependencies {
      classpath("org.springframework.boot:spring-boot-gradle-plugin:1.4.1.RELEASE")
  }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'

jar {
    baseName = 'gs-spring-boot'
    version =  '0.1.0'
}

repositories {
    ...
    mavenCentral()
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web") {
        exclude module: "spring-boot-starter-tomcat"
    }
    compile("org.springframework.boot:spring-boot-starter-jetty")
    compile("org.springframework.boot:spring-boot-starter-actuator")
    ...
}

Then you’ll add an Application.java class for initializing your web application.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        ApplicationContext ctx = SpringApplication.run(Application.class, args);
    }
}

Finally you need to add the following method to your Example.java class:

@RestController
public class Example {
    ...
    @RequestMapping(value = "/")
    public String index() {
        return "Hello, I am a very simple server";
    }
}

If you would like to try running the server now, you can do so with:

gradle build && java -jar -Dserver.port=3000 build/libs/gs-spring-boot-0.1.0.jar

Once running, open your browser to http://localhost:3000/ and you should see the text “Hello, I am a very simple server”.

See this step in Github

Express.js is a very popular and simple web framework for Node.js. You’ll need to get this setup:

Firstly you need to add the express NPM module and create a package.json file:

{
  "name": "ably-tutorials",
  "repository": "https://github.com/ably/tutorials",
  "license": "Apache-2.0",
  "engines": {
    "node": ">=0.10"
  },
  "scripts": {
    "start": "node ./server.js"
  },
  "dependencies": {
    "ably": ">=0.8",
    "express": "~4.0"
  }
}

Then you need to set up a vanilla HTTP Express.js server in server.js:

const express = require('express'),
      app = express();

app.get('/', function (req, res) {
  res.send('Hello, I am a very simple server');
});

app.listen(3000, function () {
  console.log('Web server listening on port 3000');
});

If you would like to try running the server now, you can do so with node server.js. Once running, open your browser to http://localhost:3000/ and you should see the text “Hello, I am a very simple server”.

Sinatra is a very simple and popular web server framework for Ruby. Rails is arguably more popular as a web server framework, however for the purposes of this tutorial it is overkill. Bear in mind that all the code in this tutorial can be used as is within Rails. You will need to configure routes in the routes.rb file, add the code to a controller, and then add the HTML to a view.

You’ll need to get going with a simple Sinatra web server. Add the sinatra RubyGem to your Gemfile and then run bundle install:

gem 'sinatra'

Now set up a vanilla Sinatra server in the server.rb file:

require 'sinatra'
get '/' do
  'Hello, I am a very simple server'
end

If you would like to try running the server now, you can do so with bundle exec ruby server.rb. Once running, open your browser to http://localhost:4567/ and you should see the text “Hello, I am a very simple server”.

See this step in Github

web.py is a simple web framework for Python. Django is arguably more popular as a web server framework, however for the purposes of this tutorial it is overkill.

You’ll need to get going with a simple web.py web server. Install web.py using pip:

pip install web.py

Now set up a vanilla web.py server in server.py:

import web

class index:
    def GET(self):
        return 'Hello, I am a very simple server'

urls = (
    '/', index
)

app = web.application(urls, globals())

if __name__ == "__main__":
    app.run()

In the web.py file each resource is mapped to a class, which in turn takes action depending on the HTTP method used. In this case its main domain is '/', which will be handled by the index class, and will support HTTP GET.

If you would like to try running the server now, you can do so with python server.py. Once running, open your browser to http://localhost:8080/ and you should see the text “Hello, I am a very simple server”. If you would like to change the port from which your site is available, simply add the port after the command (e.g. python server.py 1234 for port 1234).

See this step in Github

PHP has a built-in web server functionality which allows it to serve php scripts, making it excellent for the purpose of this tutorial.

Create the file index.php:

<?php
echo "Hello, I am a very simple server";

If you would like to try running the server now, you can do so with php -S 0.0.0.0:8000. Once running, open your browser to http://localhost:8000/ and you should see the text “Hello, I am a very simple server”.

See this step in Github

Sinatra is a very simple and popular web server framework for Ruby. Rails is arguably more popular as a web server framework, however for the purposes of this tutorial it is overkill. Bear in mind that all the code in this tutorial can be used as is within Rails. You will need to configure routes in the file routes.rb, add the code to a controller, and then add the HTML to a view.

Let’s get going with a simple Sinatra web server now. Add the sinatra RubyGem to your Gemfile and then run bundle install:

gem 'sinatra'

Now set up a vanilla Sinatra server in server.rb:

require 'sinatra'
get '/' do
  'Hello, I am a very simple server'
end

If you would like to try running the server now, you can do so with bundle exec ruby server.rb. Once running, open your browser to http://localhost:4567/ and you should see the text “Hello, I am a very simple server”.

See this step in Github

Step 4 – Respond to authentication requests

Before we move onto the client, you’ll need to first make sure the web server is capable of issuing token requests to clients that need to authenticate with Ably. However, instead of jumping into code, let’s quickly talk about how token authentication works and what the difference is between a Token and TokenRequest is.

When a client needs to authenticate, it will automatically send a request to the authentication URL you provide, which is normally a URL on your server. Alternatively, if you provide a callback instead of an authentication URL, it will invoke your callback and wait for it to respond with token details. See the auth options documentation for more information on the options available.

Your web server or callback, following an authentication request, is then responsible for providing the client library with a Token or a TokenRequest. The token can contain permissions (we call them capabilities) and an identity for the client, but this functionality will be discussed later in this tutorial.

For now you need to understand how token requests and tokens differ and why in most cases we recommend you issue token requests as opposed to tokens.

Tokens

All clients authenticating with Ably must use either an API key or a token. Tokens are obtained by sending a TokenRequest containing the required token spec to the Ably service. The token may include a set of capabilities (permissions such as subscribe access to a specific channel), an identity (such as the logged-in user’s unique ID) or a TTL (the time before the token expires).

Token Requests

Token requests, unlike tokens, are created and signed by your server without having to communicate with Ably. A token request is simply a JSON object that contains a pre-authorization from your server for a client, effectively stating “Ably, with this signed token, I authorize you to issue a token according to the permissions, ID and TTL specified, to whoever hands this to you”. Ably is then able to inspect the signature to ensure that the token request is indeed from your server and signed with your private API key. Ably will then issue a token to the client requesting the token. Ably ensures that token requests can only be used soon after creation and can only be used once.

Therefore, as it is possible to issue token requests without any communication with Ably (in the form of an HTTP request), we recommend that when a client needs to authenticate, you provide a signed token request. This approach minimizes the amount of work your server needs to do by distributing the task of obtaining a token from the Ably service using the token request to your clients instead.

In this step we will get the local web server ready to respond to authentication requests by issuing a token request to the requesting client.

By adding the following route to the Example.java class, it will be ready to service clients wanting to authenticate with Ably.

@RequestMapping("/auth")
public String auth(HttpServletRequest request, HttpServletResponse response) throws AblyException {

  Auth.TokenParams tokenParams = new Auth.TokenParams(); /* Use token defaults for now */

  try {
    Auth.TokenRequest tokenRequest = ablyRest.auth.createTokenRequest(null, tokenParams);
    response.setHeader("Content-Type", "application/json");
    return new Gson().toJson(tokenRequest);
  } catch (AblyException e) {
    response.setStatus(500);
    return "Error requesting token: " + e.getMessage();
  }
}

Try resetting your server again, then visit http://localhost:3000/auth to see a JSON token request in the form:

{
  "keyName": "I2ACJQ.Lv8AUQ",
  "ttl": 3600000,
  "timestamp": 1473894038255,
  "capability": "{\"*\":[\"*\"]}",
  "nonce": "f6799a8e7fa6f77b8e1dac55314789b1",
  "mac": "35nifY9SRZ8KRDfKOPIS1qYWGP16r2lD59zJo9TH8pA="
}

See this step in Github

By adding the following route to your Express.js server, it will be ready to service clients wanting to authenticate with Ably.

/* Issue token requests to clients sending a request to the /auth endpoint */
app.get('/auth', function (req, res) {
  var tokenParams = {}; /* Use token defaults for now */
  rest.auth.createTokenRequest(tokenParams, function(err, tokenRequest) {
    if (err) {
      res.status(500).send('Error requesting token: ' + JSON.stringify(err));
    } else {
      res.setHeader('Content-Type', 'application/json');
      res.send(JSON.stringify(tokenRequest));
    }
  });
});

Try running your server again with node server.js, then visit http://localhost:3000/auth to see a JSON token request in the form:

{
  "keyName": "I2ACJQ.Lv8AUQ",
  "ttl": 3600000,
  "timestamp": 1473894038255,
  "capability": "{\"*\":[\"*\"]}",
  "nonce": "f6799a8e7fa6f77b8e1dac55314789b1",
  "mac": "35nifY9SRZ8KRDfKOPIS1qYWGP16r2lD59zJo9TH8pA="
}

By adding the following route to your server, it will be ready to service clients wanting to authenticate with Ably.

require 'json'

# Issue token requests to clients sending a request to the /auth endpoint
get '/auth' do
  content_type :json
  ably.auth.create_token_request.to_json
end

Try running your server again with bundle exec ruby server.rb, then visit http://localhost:4567/auth to see a JSON token request in the form:

{
  "keyName": "I2ACJQ.Lv8AUQ",
  "ttl": 3600000,
  "timestamp": 1473894038255,
  "capability": "{\"*\":[\"*\"]}",
  "nonce": "f6799a8e7fa6f77b8e1dac55314789b1",
  "mac": "35nifY9SRZ8KRDfKOPIS1qYWGP16r2lD59zJo9TH8pA="
}

See this step in Github

By adding the following class and route to your URLs, it will be ready to service clients wanting to authenticate with Ably.

import json

# Issue token requests to clients sending a request to the /auth endpoint
class auth:
    def GET(self):
        web.header('Content-Type', 'application/json')
        return json.dumps(client.auth.create_token_request().to_dict())

# let's update URLs
urls = (
    '/', index,
    '/auth', auth
)

Try running your server again with python server.py, then visit http://localhost:8080/auth to see a JSON token request in the form:

{
  "keyName": "I2ACJQ.Lv8AUQ",
  "ttl": 3600000,
  "timestamp": 1473894038255,
  "capability": "{\"*\":[\"*\"]}",
  "nonce": "f6799a8e7fa6f77b8e1dac55314789b1",
  "mac": "35nifY9SRZ8KRDfKOPIS1qYWGP16r2lD59zJo9TH8pA="
}

See this step in Github

By adding the following script, it will be ready to service clients wanting to authenticate with Ably.

Create auth.php script:

require_once 'ably.php'
header('Content-Type: application/json');
# Issue token requests to clients sending a request to the /auth.php endpoint
echo json_encode($ably->auth->createTokenRequest()->toArray());

Try running your server again with php -S 0.0.0.0:8000 (if it’s not up already), then visit http://localhost:8000/auth.php to see a JSON token request in the form:

{
  "keyName": "I2ACJQ.Lv8AUQ",
  "ttl": 3600000,
  "timestamp": 1473894038255,
  "capability": "{\"*\":[\"*\"]}",
  "nonce": "f6799a8e7fa6f77b8e1dac55314789b1",
  "mac": "35nifY9SRZ8KRDfKOPIS1qYWGP16r2lD59zJo9TH8pA="
}

See this step in Github

Step 5 – Setting up a client to use token authenticationStep 5 – Setting up environment and client to use token authenticationStep 5 – Setup an Xcode project and prepare the client to use token authentication

Now that we have a web server running and an authentication endpoint, we are ready to set up the Ably Realtime client that uses token auth.

Firstly you need to set up a simple HTML page that will be served by the web server. Create the following HTML file named index.html in the src/main/webapp folder:

Firstly you need to create a simple Android project that will be served by the web server. To build your own Android Project, please visit the Android Developers website and get familiar with the steps necessary to set up your own application. When the project is ready, open your application’s module and modify its build.gradle file like this:

Firstly you need to set up a simple HTML page that will be served by the web server. Create the following HTML file named index.html in the same folder as server.js:

Firstly you need to set up a simple HTML page that will be served by the web server. Create the following HTML file named index.html in the same folder as server.rb:

Firstly you need to set up a simple HTML page that will be served by the web server. Replace the contents of index.php with the code below:

Firstly you need to set up a simple HTML page that will be served by the web server. Create the following HTML file named index.html in the same folder as server.py:

<html>
  <head>
    <script src="https://cdn.ably.io/lib/ably.min-1.js" type="text/javascript"></script>
  </head>
  <body>
    <h1>Token auth example</h1>
  </body>
</html>
apply plugin: 'com.android.application'
...
dependencies {
    ...
    compile 'io.ably:ably-android:1.0.0'
}

In the above example a specific version of the library is referenced, however we recommend you check which is the latest stable version for Android and always use that.

After you add necessary dependencies, you can import the AblyRealtime class into your ExampleActivity and initialize it.

public class ExampleActivity extends AppCompatActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_example);
      try {
          initAbly();
      } catch (AblyException e) {
          e.printStackTrace();
      }
  }

  private void initAbly() throws AblyException {
      ClientOptions clientOptions = new ClientOptions();
      clientOptions.authCallback = new Auth.TokenCallback() {

          @Override
          public Object getTokenRequest(Auth.TokenParams tokenParams) throws AblyException {
              String httpAuthResponse = sendRequestToServer();
              tokenRequest = new Gson().fromJson(httpAuthResponse, Auth.TokenRequest.class);
              return tokenRequest;
          }
      };
      ablyRealtime = new AblyRealtime(clientOptions);
  }
}

Now you need to serve a static home page. You should delete the index method in the Example.java class, then open the Application.java file and add following code:

import org.springframework.context.annotation.Configuration;
...
@Configuration
@SpringBootApplication
public class Application extends WebMvcConfigurerAdapter {
...
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("forward:/index.html");
        super.addViewControllers(registry);
    }
}

Try restarting your server again and visit http://localhost:3000/ to ensure the new static home page is being served up correctly. If you can see the static page, then it’s time to set up a Realtime client that uses token authentication.

Now you need to serve a static home page. Replace the code that responds to the / route (look for get '/' do ... end) with the following:

app.use('/', express.static(__dirname));

Try running your server again with node server.js and visit http://localhost:3000/ to make sure the new static home page is being served up correctly. If you can see the static page, then it’s time to set up a Realtime client that uses token authentication.

Now you need to serve a static home page. Replace the code that responds to the / route (look for app.get('/', ...) with the following:

get '/' do
  File.read('index.html')
end

Try running your server again with bundle exec ruby server.rb and visit http://localhost:4567/ to make sure the new static home page is being served up correctly. If you can see the static page, then it’s time to set up a Realtime client that uses token authentication.

Now you need to serve a static home page. Replace the code that responds to the / route (look for index class) with the following:

class index:
    def GET(self):
        html = open('index.html')
        return html.read()

Try running your server again with python server.py and visit http://localhost:8080/ to make sure the new static home page is being served up correctly. If you can see the static page, then it’s time to set up a Realtime client that uses token authentication.

Try running your server again with php -S 0.0.0.0:8000 (if it’s not up already) and visit http://localhost:8000/ to make sure the new static home page is being served up correctly. If you can see the static page, then it’s time to set up a Realtime client that uses token authentication.

Add the following into the ExampleAcitivity#initAbly method:

ablyRealtime.connection.once(ConnectionState.connected, new ConnectionStateListener() {
          @Override
          public void onConnectionStateChanged(ConnectionStateChange state) {
              /* Always do UI updates on UI thread */
              runOnUiThread(new Runnable() {
                  @Override
                  public void run() {
                      Toast.makeText(getBaseContext(),
                        "We're connected using the token request from the server /auth endpoint!", Toast.LENGTH_SHORT).show();
                  }
              });
          }
      });

By adding the following route to your server, it is now ready to service clients wanting to authenticate with Ably.

require 'json'

# Issue token requests to clients sending a request to the /auth endpoint
get '/auth' do
  content_type :json
  ably.auth.create_token_request.to_json
end

Try running your server again with bundle exec ruby server.rb and visit http://localhost:4567/auth to see a JSON token request in the form:

{
  "keyName": "I2ACJQ.Lv8AUQ",
  "ttl": 3600000,
  "timestamp": 1473894038255,
  "capability": "{\"*\":[\"*\"]}",
  "nonce": "f6799a8e7fa6f77b8e1dac55314789b1",
  "mac": "35nifY9SRZ8KRDfKOPIS1qYWGP16r2lD59zJo9TH8pA="
}

See this step in Github

Add the following above the closing </html> tag in your index.html file:

<script type="text/javascript">
  /* Set up a Realtime client that authenticates with the local web server auth endpoint */
  var realtime = new Ably.Realtime({ authUrl: '/auth' });
  realtime.connection.once('connected', function() {
    alert("We're connected using the token request from the server /auth endpoint!");
  });
</script>

Add the following above the closing </html> tag in your index.php file:

<script type="text/javascript">
  /* Set up a Realtime client that authenticates with the local web server auth endpoint */
  var realtime = new Ably.Realtime({ authUrl: '/auth.php' });
  realtime.connection.once('connected', function() {
    alert("We're connected using the token request from the server /auth endpoint!");
  });
</script>

Time for us to see what happens now. Restart the local server and refresh the page. You should receive an alert to confirm that you’re connected to Ably which means your server has successfully issued a token request to the client. The client has then obtained a token from Ably with the token request, and then subsequently authenticated and finally connected.

Time for us to see what happens now. Restart the local server and rerun your application. You should receive an alert to confirm that you’re connected to Ably which means your server has successfully issued a token request to the client. The client has then obtained a token from Ably with the token request, and then subsequently authenticated and finally connected.

Firstly you’ll need to set up an Xcode project that will serve as your client.

To build your own Xcode Project in Swift visit the Apple developer website and get familiar with steps necessary to set up your own application.
When you set up your application delete the default ViewController.swift, then add a new file by going through File → New → File… and choose Cocoa Touch Class.


Create new Cocoa Touch Class

Name your new class “ExampleViewController” and choose Swift as language:


Name new Cocoa Touch Class

After that navigate to Main.storyboard in your project, click on the ViewController that has already been added by default during the project creation. In the Utilities that are located on the right select Identity Inspector. Find the field labeled “Class” and select “ExampleViewController”.


Interface design

See this step in Github

To start using Ably you first need to install the Ably pod via CocoaPods. You need to add a Podfile to your project directory:

touch Podfile

Then add this line to your application’s Podfile:

pod 'Ably'

Install it with:

pod install

To learn more about using CocoaPods in your project visit the official CocoaPods guide.

Inside any files which will be using Ably add the following import:

import Ably

Now it’s time to set up a Realtime client that uses token authentication.
Firstly you need to create a new method that will try to connect us to Ably.
By using authCallback you don’t have to worry if the user already has a clientId.

private func connectToAbly() {

    let options = ARTClientOptions()

    options.authCallback = { params, callback in
        self.getTokenRequest() { json, error in
            do {
                callback(try ARTTokenRequest.fromJson(json!), nil)
              } catch let error as NSError {
                callback(nil, error)
                }
              }
            }

    client = ARTRealtime(options: options)
    client.connection.on { state in
      if let state = state {
          switch state.current {
          case .Connected:
              self.showAlert("Connected", message: "Successfully connected to API.")
          case .Failed:
              print( self.client.connection.errorReason)
              self.showAlert("Failed", message: "There was a problem connecting to API")
          default:
              break
          }
        }
      }
}

Now add the getTokenRequest method. This method is responsible for making a server request and obtaining a JSON response.

func getTokenRequest(completion: (NSDictionary?, ErrorType?) -> ())  {
    let requestURL: NSURL = NSURL(string: "http://localhost:4567/auth")!
    let urlRequest: NSMutableURLRequest = NSMutableURLRequest(URL: requestURL)
    let session = NSURLSession.sharedSession()
    let task = session.dataTaskWithRequest(urlRequest) {
        (data, response, error) -> Void in
        let httpResponse = response as! NSHTTPURLResponse
        let statusCode = httpResponse.statusCode
        if (statusCode == 200) {
            do{
                let json = try NSJSONSerialization
                .JSONObjectWithData(data!, options:.AllowFragments) as! NSDictionary

                completion(json, nil)
              } catch {
                self.showAlert("Error", message: "There was an error while obtaining JSON")
              }
            }
          }
          task.resume()
  }

Add this line to your viewDidLoad method:

connectToAbly()

There is one more thing to do before you can test this code. By default Apple forces its developers to use secure connections, but the server in this tutorial is really simple and will be using HTTP. Because of that the code above won’t work if you don’t change the default behavior to allow arbitrary loads. In the Project Navigator choose your project, then in the view that will appear click on your target. Next, click on the Info tab and under “Custom iOS Target Properties” add a new row by right-clicking on the table and picking “Add Row”. Type “App Transport Security Settings” then click on the + type “Allow Arbitrary Loads” and change its value to “YES”. If you have problems with these steps – see the image below:


info.plist

Time for us to see what happens now. Execute the code in a simulator. You should receive an alert to confirm that you’re connected to Ably which means your server has successfully issued a token request to the client. The client has then obtained a token from Ably with the token request, and then subsequently authenticated and finally connected.

See this step in Github

We’ve now covered the basics of client-server token authentication and your client has a means to renew the token whenever it needs one.

Step 6 – Authenticating logged in users

In the previous step we saw how easy it is to issue a token request from your server for clients that need to authenticate with Ably. However, the example is quite contrived in that it is unlikely you would want to issue tokens to anonymous users with a full set of capabilities. At present, the token issued allows all users to publish, subscribe, be present, retrieve stats and history across all channels.

In this step we’ll see how to issue subscribe only tokens limited to a single channel for anonymous users, and issue publish and subscribe tokens for logged in users. As the purpose of this tutorial is not to demonstrate how to build an authentication system for your mobile app, we will be implementing a trivial and clearly flawed authentication system so that we can keep superfluous unrelated code to a minimum.

In this step we’ll see how to issue subscribe only tokens limited to a single channel for anonymous users, and issue publish and subscribe tokens for logged in users. As the purpose of this tutorial is not to demonstrate how to build an authentication system for your website, we will be implementing a trivial and clearly flawed authentication system so that we can keep superfluous unrelated code to a minimum.

Time to get started. Firstly you will add an EditText element and a Button element into our layout, creating simple login form. Add the following into the activity_example.xml file:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_example"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Token auth example" />
    <EditText
        android:id="@+id/etClientId"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="ClientId" />
    <Button
        android:id="@+id/btLogin"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Login" />
    <Button
        android:id="@+id/btLogout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Logout" />
    <TextView
        android:id="@+id/tvCapabilities"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Capabilities" />
</LinearLayout>

Time to get started. Firstly you will add two panels, one that contains a simple login form, and the other with a logout link to the HTML page. Add the following beneath the </h1> tag in your index.html file:

<div id="panel-anonymous">
  <h3>Login</h3>
  <form action="/login">
    <input type="text" name="username" placeholder="Enter your username">
    <input type="submit" value="Login">
  </form>
</div>
<div id="panel-logged-in">
  Your are logged in. <a href="/logout">Log out</a>
</div>

Time to get started. Firstly you will add two panels, one that contains a simple login form, and the other with a logout link to the HTML page. Add the following beneath the </h1> tag in your index.php file:

<div id="panel-anonymous">
  <h3>Login</h3>
  <form action="/login.php">
    <input type="text" name="username" placeholder="Enter your username">
    <input type="submit" value="Login">
  </form>
</div>
<div id="panel-logged-in">
  Your are logged in. <a href="/logout.php">Log out</a>
</div>

Now we need to enable the login and logout functionality in the web server. In order to keep this tutorial simple, when a user logs in we’ll create a cookie, and when they log out we’ll clear the cookie. Add the following routes to your Example.java file.

@RequestMapping(value = "/login", method = RequestMethod.GET)
public String login(@RequestParam(name = "username", defaultValue = "anonymous")
    String username, HttpServletResponse response) throws IOException {
    response.addCookie(new Cookie("username", username));
    response.sendRedirect("/");
    return "redirect:/";
}

@RequestMapping(value = "/logout", method = RequestMethod.GET)
public String logout(HttpServletRequest request, HttpServletResponse response) throws IOException {
    for(Cookie cookie : request.getCookies()) {
        if(cookie.getName().equalsIgnoreCase("username")){
            cookie.setValue(null);
            cookie.setMaxAge(0);
            cookie.setPath(request.getContextPath());
            response.addCookie(cookie);
        }
    }
    response.sendRedirect("/");
    return "redirect:/";
}

Now we need to enable the login and logout functionality in the web server. In order to keep this tutorial simple, when a user logs in we’ll need to create a cookie, and when they log out we’ll clear the cookie. Add the following routes to your server.js file.

/* Set a cookie when the user logs in */
app.get('/login', function (req, res) {
  /* Login the user without credentials.
     This is an over simplified authentication system
     to keep this tutorial simple */
  if (req.query['username']) {
    res.cookie('username', req.query['username']);
    res.redirect('/');
  } else {
    res.status(500).send('Username is required to login');
  }
});

/* Clear the cookie when the user logs outs */
app.get('/logout', function (req, res) {
  res.clearCookie('username');
  res.redirect('/');
});

Now we need to enable the login and logout functionality in the web server. In order to keep this tutorial simple, you’ll add a username query parameter to the /auth route. If it exists, it means user wants to log in, and if it doesn’t they want to log out. Modify the /auth route in you server.js file.

var tokenParams;
if (req.query['username']) {
  tokenParams = {
    'capability': { '*': ['publish', 'subscribe'] },
    'clientId': req.cookies.username
  };
} else {
  tokenParams = {
    'capability': { 'notifications': ['subscribe'] }
  };
}

Now we need to enable the login and logout functionality in the web server. In order to keep this tutorial simple, when a user logs in we’ll set a cookie, and when they log out we’ll clear the cookie.

You’ll need to add cookie support to Sinatra, so add the following to your Gemfile and bundle install:

gem 'sinatra-contrib'

Add the following routes to your server.rb file.

require 'sinatra/cookies'

# Set a cookie when the user logs in
get '/login' do
  # Login the user without credentials.
  # This is an over simplified authentication system
  # to keep this tutorial simple
  if request.params['username']
    cookies[:username] = request.params['username']
    redirect to('/')
  else
    status 500
    'Username is required to login'
  end
end

# Clear the cookie when the user logs outs
get '/logout' do
  cookies.delete 'username'
  redirect to('/')
end

Now we need to enable the login and logout functionality in the web server. In order to keep this tutorial simple, when a user logs in we’ll set a cookie, and when they log out we’ll clear the cookie.

Add the following classes to your server.py file.

# Set cookie when the user logs in
class login:
    def GET(self):
        username = web.input().get('username')
        if username is not None:
            web.setcookie('username', username)
            raise web.seeother('/')
        else:
            raise web.InternalError('Username is required to login')

# Clear the cookie when the user logs outs
class logout:
    def GET(self):
        web.setcookie('username', None, -1)
        raise web.seeother('/')

# update URLs
urls = (
    '/', index,
    '/auth', auth,
    '/login', login,
    '/logout', logout
)

Now we need to enable the login and logout functionality in the web server. In order to keep this tutorial simple, when a user logs in we’ll set a cookie, and when they log out we’ll clear the cookie.

You’ll need to create two scripts that will serve as your login and logout functionality.

First, create a login.php file containing:

<?php
if (isset($_REQUEST['username'])) {
  setcookie('username', $_REQUEST['username']);
  header('Location: /', true, 302);
} else {
  http_response_code(500);
  echo "Username is required to login";
}

Secondly, create a logout.php file to deal with logging out:

<?php
setcookie('username', null, -1, '/');
header('Location: /', true, 302);

Let’s add logged in and logged out states for our layout. To switch between them, you’ll need to add logic into your ExampleActivity. Add the following inside your class:

private TextView tvCapabilities;
private EditText etClientId;
private SharedPreferences preferences;
private boolean firstStart = true;

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    preferences = PreferenceManager.getDefaultSharedPreferences(this);
    setUI();
    ...
}

private void setUI() {
    etClientId = (EditText) findViewById(R.id.etClientId);
    tvCapabilities = (TextView) findViewById(R.id.tvCapabilities);
    findViewById(R.id.btLogin).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    authenticate(etClientId.getEditableText().toString());
                }
            }).start();
        }
    });
    findViewById(R.id.btLogout).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    authenticate(null);
                }
            }).start();
        }
    });
}

private void authenticate(String clientId) {
    final Auth.TokenParams params = new Auth.TokenParams();
    params.clientId = clientId;
    try {
        ablyRealtime.auth.requestToken(params, null);
    } catch (AblyException e) {
        e.printStackTrace();
    }
}

private void initAbly() throws AblyException {
    ...
    clientOptions.authCallback = new Auth.TokenCallback() {

        @Override
        public Object getTokenRequest(Auth.TokenParams tokenParams) throws AblyException {
            if (firstStart) {
                firstStart = false;
                String clientId = preferences.getString("clientId", null);
                if (clientId != null) {
                    tokenParams.clientId = tokenRequest.clientId;
                }
            }
            String httpAuthResponse = sendRequestToServer(tokenParams.clientId);
            tokenRequest = new Gson().fromJson(httpAuthResponse, Auth.TokenRequest.class);
            preferences.edit().putString("clientId", httpAuthResponse).commit();
            setButtonsState();
            return tokenRequest;
        }
    };
    ...
}

private void setButtonsState() {
    runOnUiThread(new Runnable() {
        public void run() {
            etClientId.setText(tokenRequest.clientId);
            tvCapabilities.setText(tokenRequest.capability);
            findViewById(R.id.btLogin).setVisibility(tokenRequest.clientId == null ? View.VISIBLE : View.GONE);
            findViewById(R.id.etClientId).setEnabled(tokenRequest.clientId == null);
            findViewById(R.id.btLogout).setVisibility(tokenRequest.clientId == null ? View.GONE : View.VISIBLE);
        }
    });
}

Remember that from your Android emulator, the localhost address is 10.0.2.2. If you want to access your server from a physical device, just research setting up a public IP address.

Both the logged in and anonymous HTML panels will currently show on the HTML page. You should now add hide or show functionality based on the cookie set above. Add the following just before the final </script> tag in index.html

Both the logged in and anonymous HTML panels will currently show on the HTML page. You should now add hide or show functionality based on the cookie set above. Add the following just before the final </script> tag in index.php

var loggedIn = document.cookie.indexOf('username') >= 0;
document.getElementById('panel-anonymous').
  setAttribute('style', "display: " + (loggedIn ? 'none' : 'block'));
document.getElementById('panel-logged-in').
  setAttribute('style', "display: " + (loggedIn ? 'block' : 'none'));

Now that you have the means to determine if a user is logged in or logged out using the session cookie, you can issue restricted subscribe-only token requests for anonymous users and publish and subscribe token requests for logged in users. Replace the Example#auth method body with the following:

String username = null;
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
    if (cookie.getName().equalsIgnoreCase("username")) {
        username = cookie.getValue();
        break;
    }
}
Auth.TokenParams tokenParams = new Auth.TokenParams();
if (username == null) {
    tokenParams.capability = Capability.c14n("{ 'notifications': ['subscribe'] }");
} else {
    tokenParams.capability = Capability.c14n("{ '*': ['publish', 'subscribe'] }");
    tokenParams.clientId = username;
}
Auth.TokenRequest tokenRequest = null;
try {
    tokenRequest = ablyRest.auth.createTokenRequest(null, tokenParams);
    response.setHeader("Content-Type", "application/json");
    return new Gson().toJson(tokenRequest);
} catch (AblyException e) {
    response.setStatus(500);
    return "Error requesting token: " + e.getMessage();
}

Now that you have the means to determine if a user is logged in or logged out using the session cookie, you can issue restricted subscribe-only token requests for anonymous users and publish and subscribe token requests for logged in users. Replace the var tokenParams = {}; code in your server.js with the following:

var tokenParams;
/* Check if the user is logged in */
if (req.cookies.username) {
  /* Issue a token request with pub & sub permissions on all channels +
     configure the token with an identity */
  tokenParams = {
    'capability': { '*': ['publish', 'subscribe'] },
    'clientId': req.cookies.username
  };
} else {
  /* Issue a token with subscribe privileges restricted to one channel
     and configure the token without an identity (anonymous) */
  tokenParams = {
    'capability': { 'notifications': ['subscribe'] }
  };
}

Unfortunately Express.js is very lightweight and does not support cookie parsing out of the box. You need to add the cookie-parser NPM module to Express.js. Add the following to your package.json file:

{
  ...
  "dependencies": {
    "ably": ">=0.8",
    "express": "~4.0",
    "cookie-parser": "~1.4"
  }
}

And add the following to the top of your server.js file, beneath the Express.js require, so that cookies are parsed:

const cookieParser = require('cookie-parser');
app.use(cookieParser());

Now that you have a means to determine if a user is logged in or logged out using the session cookie, you can issue restricted subscribe-only token requests for anonymous users and publish and subscribe token requests for logged in users. Replace the get '/auth' do ... end code in your server.rb with the following:

require 'sinatra/cookies'

# Allow cookies to be read in the browser
set :cookie_options, httponly: false

# Issue token requests to clients sending a request to the /auth endpoint
get '/auth' do
  content_type :json

  # Check if the user is logged in
  token_params = if cookies[:username]
    # Issue a token request with pub & sub permissions on all channels +
    #   configure the token with an identity
    {
      capability: { '*' => ['publish', 'subscribe'] },
      client_id: cookies[:username]
    }
  else
    # Issue a token with subscribe privileges restricted to one channel
    #   and configure the token without an identity (anonymous)
    {
      capability: { 'notifications' => ['subscribe'] }
    }
  end
  ably.auth.create_token_request(token_params).to_json
end

Now that you have the means to determine if a user is logged in or logged out using the session cookie, you can issue restricted subscribe-only token requests for anonymous users and publish and subscribe token requests for logged in users. Replace the code for auth class with the following:

class auth:
    def GET(self):
        username = web.cookies().get('username')
        if username is not None:
            token_params = {
                'capability': {
                    '*': ['publish', 'subscribe']
                },
                'client_id': username
            }
        else:
            token_params = {
                'capability': {
                    'notifications': ['subscribe']
                }
            }
        web.header('Content-Type', 'application/json')
        return json.dumps(client.auth.create_token_request(token_params).to_dict())

Now that you have the means to determine if a user is logged in or logged out using the session cookie, you can issue restricted subscribe-only token requests for anonymous users and publish and subscribe token requests for logged in users. Replace the code in your auth.php with the following:

<?php
require_once 'ably.php';
// Check if the user is logged in
if (isset($_COOKIE['username'])) {
  // Issue a token request with pub & sub permissions on all channels +
  // configure the token with an identity
  $tokenParams = [
    'capability' => [
      '*' => ['publish', 'subscribe']
    ],
    'clientId'  => $_COOKIE['username']
  ];
} else {
  // Issue a token with subscribe privileges restricted to one channel
  // and configure the token without an identity (anonymous)
  $tokenParams = [
    'capability' => [
      'notifications' => ['subscribe']
    ]
  ];
}
header('Content-Type: application/json');
echo json_encode($ably->auth->createTokenRequest($tokenParams)->toArray());

Finally, before you test this new functionality, update the Toast message so that it shows the authentication details after it connects to Ably. Replace the current Toast message with the following:

String user = ablyRealtime.auth.getTokenAuth().getTokenDetails().clientId;
String capability = ablyRealtime.auth.getTokenAuth().getTokenDetails().capability;
Toast.makeText(getBaseContext(), "You are now connected to Ably \n" +
                "User: " + user + " \n" +
                "Capabilities: " + capability, Toast.LENGTH_SHORT).show();

Finally, before you test this new functionality, update the alert so that it shows the authentication details after it connects to Ably. Replace alert("We're connected... with the following:

var user = realtime.auth.tokenDetails.clientId || 'anonymous';
var capability = realtime.auth.tokenDetails.capability;
alert(
  'You are now connected to Ably \n' +
  'User: ' + user + ' \n' +
  'Capabilities: ' + capability
);

Ok, we’re ready to see all of this in action. Restart the local server node server.js and then rerun your application. You should receive a Toast message to confirm that you’re connected as an anonymous user with limited capabilities as follows:

Ok, we’re ready to see all of this in action. Restart the local server with earlier gradle command and then refresh the page at http://localhost:3000/. You should receive an alert to confirm that you’re connected as an anonymous user with limited capabilities as follows:

Time to get started. We need to check if the user provided his username, and then based on that issue rights capabilities. Replace the get '/auth' do ... end code in your server.rb with the following:

# Issue token requests to clients sending a request to the /auth endpoint
get '/auth' do
  content_type :json

  # Check if the user provided a login
  token_params = if params[:username]
    # Issue a token request with pub & sub permissions on all channels +
    #   configure the token with an identity
    {
      capability: { '*' => ['publish', 'subscribe'] },
      client_id: params[:username]
    }
    else
    # Issue a token with subscribe privileges restricted to one channel
    #   and configure the token without an identity (anonymous)
    {
      capability: { 'notifications' => ['subscribe'] }
    }
  end
    ably.auth.create_token_request(token_params).to_json
  end

Now we will need to customize the client. If you have not previously had experience building a basic user interface in Xcode, please refer to the Apple developer guide on how to build a simple UI and also learn more about adding IBOutlets and IBActions.

Firstly, add a login button and a textfield so that the user can provide their chosen username. Go to your ExampleViewController and add a UIButton from Object library. Name the action “loginAction”.


Bind action

In a similar fashion add one UILabel and change its text to “Username:”, then add UITextField and connect it. Name it “usernameText”.
Your ExampleViewController should look similar to this view:


Login view

Now add another ViewController form to Object Library. Create a new Cocoa Touch Class named LogoutViewController just like you did for ExampleViewController.

In this view controller add one UILabel with a message that the user is logged in. In addition, add a UIButton, but don’t connect it to any IBAction.

Your LogoutViewController should look similar to this view:


Logout view

To define the flow between the ExampleViewController and the LogoutViewController you will need to use segues. If you are not familiar with them, please refer to the Apple developer guide on how they work.

Firstly in your Storyboard add a new “Present Modally” action segue. Name it “logoutSegue”.


Create segue

In your ExampleViewController class add a method that will make our view controller perform the segue:

private func performSegue() {
        self.performSegueWithIdentifier("logoutSegue", sender: self)
}

Now you need to change the action that is performed when the user clicks on “OK” when the alert is shown. Change this line:

alertController.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil)

To this:

alertController.addAction(UIAlertAction(title: "OK", style: .Default, handler: {action in
          if success {
                  self.performSegue()
                } else {
                  return
                }
              }))

Now you need to change the method that connects us to Ably. If the user doesn’t provide their username then you shouldn’t pass any parameters to your server. Equally when the textfield is filled you’ll need to use its contents as the username.

private func connectToAbly() {
  var requestURL = NSURL()

  let options = ARTClientOptions()
  if let clientId = usernameText.text where !clientId.isEmpty {
      requestURL = NSURL(string: "http://localhost:4567/auth?username=\(clientId)")!
    } else {
        requestURL = NSURL(string: "http://localhost:4567/auth")!
    }

    options.authCallback = { params, callback in
      self.getTokenRequest(requestURL) { json, error in
          do {
              callback(try ARTTokenRequest.fromJson(json!), nil)
            } catch let error as NSError {
              callback(nil, error)
              }
          }
        }

    client = ARTRealtime(options: options)
    client.connection.on { state in
        if let state = state {
            switch state.current {
              case .Connected:
                self.updateSuccessState()
                case .Failed:
                print( client.connection.errorReason)
                self.showAlert("Failed",
                message: "There was a problem connecting to API", success: false)
              default:
                  break
              }
            }
        }
}

You also need to update the getTokenRequest method so that it will use the correct URL request:

func getTokenRequest(params: NSURL, completion: (NSDictionary?, ErrorType?) -> ())  {
  let requestURL: NSURL = params
  let urlRequest: NSMutableURLRequest = NSMutableURLRequest(URL: requestURL)
  let session = NSURLSession.sharedSession()
  let task = session.dataTaskWithRequest(urlRequest) {
      (data, response, error) -> Void in

      let httpResponse = response as! NSHTTPURLResponse
      let statusCode = httpResponse.statusCode

      if (statusCode == 200) {
          do{
              let json = try NSJSONSerialization
              .JSONObjectWithData(data!, options:.AllowFragments) as! NSDictionary

              completion(json, nil)
            } catch {
              self.showAlert("Error",
                              message: "There was an error while obtaining JSON", success: false)
            }
          }
        }
        task.resume()
    }

The method that configures the message that is shown on successful login looks like this:

private func updateSuccessState() {
    var alertMessage = ""
    if let clientId = client.auth.clientId {
        alertMessage = "You are now connected to Ably \n
        User: \(clientId) \n Capabilities: {\"*\":[\"publish\",\"subscribe\"]}"
      } else {
        alertMessage = "You are now connected to Ably \n
        User: anonymous \n Capabilities: {\"notifications\":[\"subscribe\"]}"
    }
    self.showAlert("Connected", message: alertMessage, success: true)
  }

The last thing you’ll need to do is perform a logout action. You didn’t connect the logout button to an action because you will need to connect it to a segue right now. In your Storyboard hold ctrl and right-click the button and drag it to ExampleViewController just like the earlier segue. Name it “toLoginSegue”. When the user taps the logout button, before the segue is performed you’ll need to close the connection to Ably and nullify the instance. All the actions that should be done before performing the segue can be done in the prepareForSegue method in your LogoutViewController:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
    if segue.identifier == "toLoginSegue" {
        client.connection.close()
        client = nil
      }
    }

We’re now ready to see all of this in action. Restart the local server bundle exec ruby server.rb and then restart your simulation. Now when you tap on login you should receive an alert to confirm that you’re connected as an anonymous user with limited capabilities as follows:

Ok, we’re ready to see all of this in action. Restart the local server node server.js and then refresh the page at http://localhost:3000/. You should receive an alert to confirm that you’re connected as an anonymous user with limited capabilities as follows:

Ok, we’re ready to see all of this in action. Restart the local server bundle exec ruby server.rb and then refresh the page at http://localhost:4567/. You should receive an alert to confirm that you’re connected as an anonymous user with limited capabilities as follows:

Ok, we’re ready to see all of this in action. Restart the local server python server.py and then refresh the page at http://localhost:8080/. You should receive an alert to confirm that you’re connected as an anonymous user with limited capabilities as follows:

Ok, we’re ready to see all of this in action. Restart the local server php -S 0.0.0.0:8000 and then refresh the page at http://localhost:8000/. You should receive an alert to confirm that you’re connected as an anonymous user with limited capabilities as follows:


Token auth details for anonymous

Now enter a username and click “login”, and you should receive an alert confirming that you are authenticated with Ably as an identified user with additional privileges to subscribe and publish on all channels as follows:

Token auth details for logged in user Mike


Token auth details for anonymous

Now enter a username and click “Login”, and you should receive an alert confirming that you are authenticated with Ably as an identified user with additional privileges to subscribe and publish on all channels as follows:

Token auth details for logged in user Mike

We’ve covered a lot of ground in this tutorial. However authentication is one of the more challenging aspects to understand as it requires you to have a good overall understanding of how it all works. We strongly recommend you check out the links below for essential further reading to help you understand authentication in more detail for use in your servers and apps.

Download tutorial source code

The complete source code for each step of this tutorial is available on Github.

We recommend that you clone the repo locally:

git clone https://github.com/ably/tutorials.git

Checkout the tutorial branch:

git checkout token-authentication-android

Then run the demo locally by adding your Ably API key to server.js and running the demo node server.js

Finally run the demo on your Android device. Check Android Developers website if you are not familiar on how to run an Android Project.

The complete source code for each step of this tutorial is available on Github.

We recommend that you clone the repo locally:

git clone https://github.com/ably/tutorials.git

Checkout the tutorial branch:

git checkout token-authentication-java

And then run the demo locally by adding your Ably API key to Example.java and running the demo:

gradle build && java -jar -Dserver.port=3000 build/libs/gs-spring-boot-0.1.0.jar

The complete source code for each step of this tutorial is available on Github.

We recommend that you clone the repo locally:

git clone https://github.com/ably/tutorials.git

Checkout the tutorial branch:

git checkout token-authentication-nodejs

And then run the demo locally by adding your Ably API key to server.js and running the demo node server.js

The complete source code for each step of this tutorial is available on Github.

We recommend that you clone the repo locally:

git clone https://github.com/ably/tutorials.git

Checkout the tutorial branch:

git checkout token-authentication-ruby

And then run the demo locally by adding your Ably API key to server.rb and running the demo bundle exec ruby server.rb

The complete source code for each step of this tutorial is available on Github.

We recommend that you clone the repo locally:

git clone https://github.com/ably/tutorials.git

Checkout the tutorial branch:

git checkout token-authentication-python

And then run the demo locally by adding your Ably API key to server.py, install the required libraries:

pip install ably web.py

and run the demo python server.py.

The complete source code for each step of this tutorial is available on Github.

We recommend that you clone the repo locally:

git clone https://github.com/ably/tutorials.git

Checkout the tutorial branch:

git checkout token-authentication-php

And then run the demo locally by adding your Ably API key to ably.php, install composer dependencies with:

composer install

and running the demo php -S 0.0.0.0:8000.

The complete source code for each step of this tutorial is available on Github

We recommend that you clone the repo locally:

git clone https://github.com/ably/tutorials.git

Checkout the tutorial branch:

git checkout token-authentication-swift

In the project directory simply run:

pod install

And then run the demo locally by adding your Ably API key to server.rb and running the demo bundle exec ruby server.rb
Open example.xcworkspace and build the demo on your preferred iPhone simulator or device.

Next steps

1. Find out how Basic Auth and Token Auth differ and how to choose the right authentication scheme
2. Read up on Basic Auth and how to use Basic Auth on your server using the REST library
3. Read up on Token Auth and how to use Token Auth on a client using the Realtime library
4. Understand and see some examples of how to define capabilities for tokens and token requests
5. Discover how identities in tokens allow clients and servers to trust other clients’ identities validated and provided by your servers
6. Learn more about other Ably features by stepping through our other Ably tutorials
7. Gain a good technical overview of how the Ably realtime platform works
8. Get in touch if you need help


Ready to get started?

Our free plan includes 3m messages per month, 100 peak connections, 100 peak channels, and loads of features.