API-Keys

Last updated 16 March 2017
Table of contents

API-Keys

To secure the use of the API-Keys, you can include a lot of limitations on what the keys can do.

The limitations

There is a variety of limitations you can embed in the API-Keys. All of these limits can be easily combined to make it almost impossible to use an API key to crawl your data.

You can create, manage and configure the API Keys in the Credentials tab of your dashboard.

ACL

Api keys 1

  • search: allows search
  • browse: allows retrieving all index content via the browse API
  • addObject: allows add/update an object in the index
  • deleteObject: allows deleting an existing object
  • listIndexes: allows listing all accessible indices
  • deleteIndex: allows deleting index content
  • settings: allows retrieving index settings
  • editSettings: allows changing index settings
  • analytics: allows retrieving analytics through the analytics API

Indices

Restrict to one or several indices based on their name: it can be a prefix or suffix of the indices name (use the * to perform the globbing). For example, use dev_* to give access to all indices whose name begins by dev_ and products to restrict the API key only to the index called products.

Rate limit

Restrict the number of API calls by allowing a set number of API calls per hour and per IP.

Number of records retrieved

Restrict the number of hits per API call: by default an API call can retrieve up to 1000 hits, but if your application only needs 10 hits per API call you can set this limit to 10.

Expiration

You can generate ephemeral API keys that can be used to grant temporary access to your data. We recommend using the Secured API key feature (see below) with time restriction instead of adding a limit on the API keys since it can take few seconds to have the new key propagated on all machines.

Custom limitations

We created a feature called Secured API Keys that lets you create custom limitations on the API keys, by forcing some search parameters to a fixed value.

Revoke an API key

You can revoke an API key in the Credentials tab of your dashboard. It will instantly become unusable.

Secured API-Keys

How it works

Sometimes you want some of your end users to have access to only a subset of your data. That can be achieved by using a Secured API key.

The goal of a secured API key is to ensure a set of query parameters cannot be changed by the end user. In order to do that, we compute a HMAC SHA-256 hash between one of your API keys that is used as a secret and the set of query parameters you want to enforce.

Here is how it works:

  1. On your backend, you use our API Client to compute the hash with a set of query parameters that you want to have applied in a secure way. The method to do that is generate_secured_api_key. The input is the API key that you want to use and the query parameters. The output is a hash containing inputs encoded in base 64. This method is just a hash computation, there is no network call to our service.
  2. You pass this hash to the end-user browser or mobile app and the string is used as an API Key.
  3. In our backend, we will scan all of your API keys and compute the hash corresponding to the set of query parameters. When the hash matches one key, this key, and associated restrictions, will be used to perform the query and the query parameters will be used. If the user tries to change the forced query parameters in the string, then the hash won’t match and the query will be rejected.

The key that you use to generate a hash must be kept secret and should never communicated to the end user or embedded in a mobile application. This would break the security of this method. You also need to keep in mind that if you have one day communicated one of your search-only API key, you should revoke all of them before moving to a secured API-Keys approach. It is easier to go for the secured API keys approach from day one.

The list of query parameters that are useful to set in the secured API-keys are the following:

  • filters: this filter allows you to restrict access only to records that match those conditions (it is usually used to represent ACL). The conditions follow Unified Filter Parameter syntax.

  • validUntil: this parameter is useful to create ephemeral API keys. You can specify a date that the key will be usable until. The date is a unix timestamp (time in seconds since 0 hours, 0 minutes, 0 seconds, January 1, 1970, Coordinated Universal Time).

  • restrictIndices: allows you to restrict the query to only be valid for one of several indices.

  • restrictSources: allows you to restrict the API key to only be valid for one IPv4 network. The source is a network in decimal notation with the netmask length: 192.168.1.0/24. If you want to restrict for one specific IP, use notation: 192.168.1.1/32.

  • userToken: allows you to apply the rate limit on a user token instead of the user IP. This is useful if your users are authenticated to avoid problems with one IP been shared by a lot of users.

Ensure you’re using a Search-Only API key, you WON’T be able to use the ADMIN api key.

All filtering query parameters (filters, facetFilters, etc.) will do an AND between the enforced value and the submitted one. For other parameters, we’ll only use the enforced value and ignore the submitted one.

Let’s see how it works with two examples:

Example 1

To ensure your users will only be able to search in their own records, you’ll need to:

  • Identify each of your records with its associated user ID (in this example we’ll use a user_id numeric attribute).
  • Generate a secured API key filtered on a specific user ID.
  • Do the search with this new secured API key.
  • If the logged-in user has ID=42, you can generate his secured & public API key using the following code:
public_key = Algolia.generate_secured_api_key('NewSearchOnlyAPIKeyKeptPrivate', {filters: 'user_42', validUntil: TIMESTAMP_IN_ONE_HOUR})
public_key = Algolia.generate_secured_api_key('NewSearchOnlyAPIKeyKeptPrivate', {filters: 'user_42', validUntil: TIMESTAMP_IN_ONE_HOUR})
public_key = client.generate_secured_api_key('NewSearchOnlyAPIKeyKeptPrivate', {filters: 'user_42', validUntil: TIMESTAMP_IN_ONE_HOUR})
var public_key = client.generateSecuredApiKey('NewSearchOnlyAPIKeyKeptPrivate', {filters: 'user_42', validUntil: TIMESTAMP_IN_ONE_HOUR});
<?php
$public_key = $client->generateSecuredApiKey('NewSearchOnlyAPIKeyKeptPrivate', array("filters" => 'user_42', "validUntil" => TIMESTAMP_IN_ONE_HOUR));
<?php
$public_key = $client->generateSecuredApiKey('NewSearchOnlyAPIKeyKeptPrivate', array("filters" => 'user_42', "validUntil" => TIMESTAMP_IN_ONE_HOUR));
String publicKey = client.generateSecuredApiKey("NewSearchOnlyAPIKeyKeptPrivate", new Query().setFilters("user_42").setValidUntil(TIMESTAMP_IN_ONE_HOUR));
params := algoliasearch.Map{
  "filters": "_tags:user_42",
}
key, err := client.GenerateSecuredAPIKey("YourSearchOnlyApiKey", params)
string publicKey = client.GenerateSecuredApiKey("NewSearchOnlyAPIKeyKeptPrivate", "filters=user_42&validUntil=TIMESTAMP_IN_ONE_HOUR");
String publicKey = client.generateSecuredApiKey("NewSearchOnlyAPIKeyKeptPrivate", Query(filters = Some("user_42"), validUntil = Some(TIMESTAMP_IN_ONE_HOUR));

Be sure to use the latest version of your API client on the backend side to generate the secured api key, in the previous implementations, you needed to specify the X-Algolia-QueryParameters to use this generated key: client.setExtraHeader('X-Algolia-QueryParameters', 'filters=user_id%3d42'); // user_id=42

And configure the API client used for the search with the following code preventing the user from searching any content that doesn’t match the ID=42:

var client = algoliasearch("65YSYSNYHU", 'PublicApiKeyGeneratedForUser42');
var index = client.initIndex('YourIndex');
index.search($('#q').val(), function searchDone(err, content) {
  if (err) {
    console.error(err);
    return;
  }
  console.log(content);
});

Example 2

Let’s say you have both public and user specific records in your application. Adding a _tags:[“public”] or _tags:[“public”, “user_42”] attribute to your records will allow you to filter the future queries with filters: 'public OR user_42' to retrieve public OR private content owned by user 42.

If the logged-in user has ID=42 and you want the API key to be valid for 1 hour, you can generate their secured & public API key using the following code:

public_key = Algolia.generate_secured_api_key('NewSearchOnlyAPIKeyKeptPrivate', {filters: 'public OR user_42', validUntil: TIMESTAMP_IN_ONE_HOUR})
public_key = Algolia.generate_secured_api_key('NewSearchOnlyAPIKeyKeptPrivate', {filters: 'public OR user_42', validUntil: TIMESTAMP_IN_ONE_HOUR})
public_key = client.generate_secured_api_key('NewSearchOnlyAPIKeyKeptPrivate', {filters: 'public OR user_42', validUntil: TIMESTAMP_IN_ONE_HOUR})
var public_key = client.generateSecuredApiKey('NewSearchOnlyAPIKeyKeptPrivate', {filters: 'public OR user_42', validUntil: TIMESTAMP_IN_ONE_HOUR});
<?php
$public_key = $client->generateSecuredApiKey('NewSearchOnlyAPIKeyKeptPrivate', array("filters" => 'public OR user_42', "validUntil" => TIMESTAMP_IN_ONE_HOUR));
<?php
$public_key = $client->generateSecuredApiKey('NewSearchOnlyAPIKeyKeptPrivate', array("filters" => 'public OR user_42', "validUntil" => TIMESTAMP_IN_ONE_HOUR));
String publicKey = client.generateSecuredApiKey("NewSearchOnlyAPIKeyKeptPrivate", new Query().setFilters("public OR user_42").setValidUntil(TIMESTAMP_IN_ONE_HOUR));
params := algoliasearch.Map{
  "filters":   "_tags:user_42",
  "userToken": "user_42",
}
key, err := client.GenerateSecuredAPIKey("YourSearchOnlyApiKey", params)
string publicKey = client.GenerateSecuredApiKey("NewSearchOnlyAPIKeyKeptPrivate", "filters=public+OR+user_42&validUntil=TIMESTAMP_IN_ONE_HOUR");
String publicKey = client.generateSecuredApiKey("NewSearchOnlyAPIKeyKeptPrivate", Query(filters = Some("public OR user_42"), validUntil = Some(TIMESTAMP_IN_ONE_HOUR));

And configure the API client used for the search with the following code avoiding the user for searching any content that doesn’t match the tags public OR user_42:

var client = algoliasearch('65YSYSNYHU', 'PublicApiKeyGeneratedForUser42');
var index = client.initIndex('YourIndex');
index.search($('#q').val(), function searchDone(err, content) {
  if (err) {
    console.error(err);
    return;
  }
  console.log(content);
});

Did you find this page helpful?

We're always looking for advice to help improve our documentation! Please let us know what's working (or what's not!) - we're constantly iterating thanks to the feedback we receive.

Send us your suggestions!