Integrations (OAuth)

In Getting Started we showed you just how easy it is to send messages using your own access token. But what if your app needs to send messages on behalf of someone else? That's where Integrations and OAuth come in.

Keep in mind that you don't need to register an integration to explore the APIs. The best way to learn the APIs is to use your own Access Token to create rooms, play with messages, etc. If you're sure that your integrations require authenticating on behalf of another Spark user, read on.

What are Integrations?

Integrations are how you request permission to invoke Spark APIs on behalf of another user. To do this in a secure way Spark supports the OAuth 2 standard which allows 3rd party integrations to get a temporary access token for authenticating API calls instead of asking users for their Spark password.

We'll get you there in a few easy steps:

  1. Register your integration with Spark
  2. Request permission using an OAuth Grant Flow
  3. Exchange the resulting Authorization Code for an Access Token
  4. Use the Access Token to make your API calls

Registering your Integration

Registering an integration with Spark is super easy. In My Apps click on the Plus Button. Click the Create an Integration button and provide some basic information like your integration's name, description and logo. This information should be user-facing since that's what they'll see in the permission dialog.

After successful registration you'll be taken to a different screen containing your integrations' newly created Client ID and Client Secret. The Client Secret will only be shown once so please copy and keep it safe!

Requesting Permission

This step requires that your integration have a user interface capable of temporarily sending users to a Cisco Spark login page. For web apps this is typically done as a popup or redirect. For mobile apps consider using a "WebView" or equivalent on your mobile platform of choice.

To kick off the flow send your user to the following URL along with a standard set of OAuth query parameters:

https://api.ciscospark.com/v1/authorize

The required query parameters are:

response_type Must be set to "code"
client_id Issued when creating your app
redirect_uri Must match one of the URIs provided during integration registration
scope A space-separated list of scopes being requested by your integration (see below)
state A unique string that will be passed back to your integration upon completion (see below)

After logging in users will see a grant dialog like this one:

Scopes

Scopes define the level of access that your integration requires. The following is a complete list of scopes and their user-facing descriptions as shown in the permission dialog.

spark:all Full access to your Cisco Spark account
spark:people_read Read your company directory
spark:rooms_read List the titles of rooms that you're in
spark:rooms_write Manage rooms on your behalf
spark:memberships_read List the people in rooms that you're in
spark:memberships_write Invite people to rooms on your behalf
spark:messages_read Read the content of rooms that you're in
spark:messages_write Post and delete messages on your behalf
spark:teams_read List the teams you are a member of
spark:teams_write Manage teams on your behalf
spark:team_memberships_read List the people in the teams that you are in
spark:team_memberships_write Add people to teams on your behalf
spark-admin:people_read Allows the application to read your company directory
spark-admin:people_write Allows the application to edit your company directory
spark-admin:organizations_read Allows the application to read your organizations
spark-admin:roles_read Allows the application to read roles available in your organization
spark-admin:licenses_read Allows the application to read licenses available in your organization
spark-admin:metrics_read Access to read metrics in your user's organization
spark-admin:events_read Access to read events in your user's organization
spark-admin:messages_write Post and delete messages in all spaces in your user's organization

Scopes that begin with spark-admin can only be granted to users with administration access in their organization. Granting this scope to non-admin users will not allow your application to perform these actions.

The spark:all scope acts as an overall aggregate for the rest of the user scopes. It requests full access to a Spark account. It does not include any spark-admin scope privileges, which may be added if necessary.

As a general best practice, your integration should request only the scope, or scopes, it needs. For example, if you are creating an integration that notifies users of updates in a third-party service, and never responds to any commands, we recommend using only the spark:messages_write scope. Applications that use the Spark SDKs to enable calling features will require the spark:all scope.

State

The state parameter is used to verify that the response from grant flow has not been tampered with along the way. It is recommended that your integration set this to a value that it verifiable once the user gives permission and the web browser is sent to your redirect_uri. A second use for this parameter is to encode basic state information like an internal user ID or the URL of the last page they were on before entering the grant flow.

Getting an Access Token

If the user granted permission to your integration, Spark will redirect the user's web browser to the redirect_uri you specified when entering the grant flow. The request to the Redirect URL will contain a code parameter in the query string like so:

http://your-server.com/auth?code=YjAzYzgyNDYtZTE3YS00OWZkLTg2YTgtNDc3Zjg4YzFiZDlkNTRlN2FhMjMtYzUz

Your integration will then need to exchange this Authorization Code for an Access Token that can be used to invoke the APIs. To do this your app will need to perform an HTTP POST to the following URL with a standard set of OAuth parameters. This endpoint will only accept an x-www-form-urlencoded body.

https://api.ciscospark.com/v1/access_token

The required parameters are:

grant_type This should be set to "authorization_code"
client_id Issued when creating your integration
client_secret Remember this guy? You kept it safe somewhere when creating your integration
code The Authorization Code from the previous step
redirect_uri Must match the one used in the previous step

Spark will then respond with JSON containing an Access Token that's good for 14 days and a Refresh Token that expires in 90 days. The Refresh Token can be used to generate a new Access Token when the current one expires:

{
 "access_token":"ZDI3MGEyYzQtNmFlNS00NDNhLWFlNzAtZGVjNjE0MGU1OGZmZWNmZDEwN2ItYTU3",
 "expires_in":1209600, //seconds
 "refresh_token":"MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTEyMzQ1Njc4",
 "refresh_token_expires_in":7776000 //seconds
}

To refresh the access token, issue a POST tohttps://api.ciscospark.com/v1/access_tokenwith the following fields:

grant_type This should be set to "refresh_token"
client_id Issued when creating your integration
client_secret Remember this guy? You kept it safe somewhere when creating your integration
refresh_token The Refresh Token you received from the previous step

Spark will then respond with JSON containing a new Access Token. Generating a new Access Token automatically renews the lifetime of your Refresh Token.

Invoking Spark APIs

Authenticating with another user's Access Token works just like your developer token; supply the token in an Authorization header like so:

GET /rooms
Authorization: Bearer THE_ACCESS_TOKEN
Accept: application/json

or in cURL it would be

curl https://api.ciscospark.com/v1/rooms \
-H "Authorization: Bearer THE_ACCESS_TOKEN" \
-H "Accept: application/json"

The Bearer part is important as it instructs Spark that this is an OAuth token instead of HTTP Basic Auth.