Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Security / User API Keys #13

Closed
ElPicador opened this issue Nov 30, 2015 · 0 comments
Closed

Security / User API Keys #13

ElPicador opened this issue Nov 30, 2015 · 0 comments
Milestone

Comments

@ElPicador
Copy link

The admin API key provides full control of all your indices.
You can also generate user API keys to control security.
These API keys can be restricted to a set of operations or/and restricted to a given index.

To list existing keys, you can use listUserKeys method:

TODO: // Lists global API Keys
client.listUserKeys();
// Lists API Keys that can access only to this index
index.listUserKeys();

Each key is defined by a set of permissions that specify the authorized actions. The different permissions are:

  • search: Allowed to search.
  • browse: Allowed to retrieve all index contents via the browse API.
  • addObject: Allowed to add/update an object in the index.
  • deleteObject: Allowed to delete an existing object.
  • deleteIndex: Allowed to delete index content.
  • settings: allows to get index settings.
  • editSettings: Allowed to change index settings.
  • analytics: Allowed to retrieve analytics through the analytics API.
  • listIndexes: Allowed to list all accessible indexes.

Example of API Key creation:

TODO: // Creates a new global API key that can only perform search actions
JSONObject res = client.addUserKey(Arrays.asList("search"));
System.out.println("Key: " + res.getString("key"));
// Creates a new API key that can only perform search action on this index
JSONObject res = index.addUserKey(Arrays.asList("search"));
System.out.println("Key: " + res.getString("key"));

You can also create an API Key with advanced settings:

  • validity: Add a validity period. The key will be valid for a specific period of time (in seconds).

  • maxQueriesPerIPPerHour: Specify the maximum number of API calls allowed from an IP address per hour. Each time an API call is performed with this key, a check is performed. If the IP at the source of the call did more than this number of calls in the last hour, a 403 code is returned. Defaults to 0 (no rate limit). This parameter can be used to protect you from attempts at retrieving your entire index contents by massively querying the index.

    Note: If you are sending the query through your servers, you must use the enableRateLimitForward("TheAdminAPIKey", "EndUserIP", "APIKeyWithRateLimit") function to enable rate-limit.

  • maxHitsPerQuery: Specify the maximum number of hits this API key can retrieve in one call. Defaults to 0 (unlimited). This parameter can be used to protect you from attempts at retrieving your entire index contents by massively querying the index.

  • indexes: Specify the list of targeted indices. You can target all indices starting with a prefix or ending with a suffix using the '' character. For example, "dev_" matches all indices starting with "dev_" and "*_dev" matches all indices ending with "_dev". Defaults to all indices if empty or blank.

  • referers: Specify the list of referers. You can target all referers starting with a prefix or ending with a suffix using the '' character. For example, "algolia.com/" matches all referers starting with "algolia.com/" and "*.algolia.com" matches all referers ending with ".algolia.com". Defaults to all referers if empty or blank.

  • queryParameters: Specify the list of query parameters. You can force the query parameters for a query using the url string format (param1=X&param2=Y...).

  • description: Specify a description to describe where the key is used.

TODO: // Creates a new global API key that is valid for 300 seconds
JSONObject param = new JSONObject();
param.put("acl", Arrays.asList("search"));
param.put("maxHitsPerQuery", 20);
param.put("maxQueriesPerIPPerHour", 100);
param.put("validity", 300);
param.put("indexes", Arrays.asList("myIndex"));
param.put("referers", Arrays.asList("algolia.com/*"));
param.put("queryParameters", "typoTolerance=strict&ignorePlurals=false");
param.put("description", "Limited search only API key for algolia.com");

JSONObject res = client.addUserKey(param);
System.out.println("Key: " + res.getString("key"));
// Creates a new index specific API key valid for 300 seconds, with a rate limit of 100 calls per hour per IP and a maximum of 20 hits
JSONObject res = index.addUserKey(param);
System.out.println("Key: " + res.getString("key"));

Update the permissions of an existing key:

TODO: // Creates a new global API key that is valid for 300 seconds
JSONObject res = client.updateUserKey("myAPIKey", Arrays.asList("search"), 300, 0, 0);
Log.d("debug", "Key: " + res.getString("key"));
// Update a index specific API key valid for 300 seconds, with a rate limit of 100 calls per hour per IP and a maximum of 20 hits
JSONObject res = index.updateUserKey("myAPIKey", Arrays.asList("search"), 300, 100, 20);
Log.d("debug", "Key: " + res.getString("key"));

Get the permissions of a given key:

TODO: // Gets the rights of a global key
client.getUserKeyACL("f420238212c54dcfad07ea0aa6d5c45f");
// Gets the rights of an index specific key
index.getUserKeyACL("71671c38001bf3ac857bc82052485107");

Delete an existing key:

TODO: // Deletes a global key
client.deleteUserKey("f420238212c54dcfad07ea0aa6d5c45f");
// Deletes an index specific key
index.deleteUserKey("71671c38001bf3ac857bc82052485107");

You may have a single index containing per user data. In that case, all records should be tagged with their associated user_id in order to add a tagFilters=user_42 filter at query time to retrieve only what a user has access to. If you're using the JavaScript client, it will result in a security breach since the user is able to modify the tagFilters you've set by modifying the code from the browser. To keep using the JavaScript client (recommended for optimal latency) and target secured records, you can generate a secured API key from your backend:

TODO: // generate a public API key for user 42. Here, records are tagged with:
//  - 'user_XXXX' if they are visible by user XXXX
String publicKey = client.generateSecuredApiKey("YourSearchOnlyApiKey", new Query().setTagFilters("user_42"));

This public API key can then be used in your JavaScript code as follow:

var client = algoliasearch('YourApplicationID', '<%= public_api_key %>');

var index = client.initIndex('indexName')

index.search('something', function(err, content) {
  if (err) {
    console.error(err);
    return;
  }

  console.log(content);
});

You can mix rate limits and secured API keys by setting a userToken query parameter at API key generation time. When set, a unique user will be identified by her IP + user_token instead of only by her IP. This allows you to restrict a single user to performing a maximum of N API calls per hour, even if she shares her IP with another user.

TODO: // generate a public API key for user 42. Here, records are tagged with:
//  - 'user_XXXX' if they are visible by user XXXX
String publicKey = client.generateSecuredApiKey("YourSearchOnlyApiKey", new Query().setTagFilters("user_42").setUserToken("42"));

This public API key can then be used in your JavaScript code as follow:

var client = algoliasearch('YourApplicationID', '<%= public_api_key %>');

var index = client.initIndex('indexName')

index.search('another query', function(err, content) {
  if (err) {
    console.error(err);
    return;
  }

  console.log(content);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant