Combining restricted and open search with securedApiKey

Hi there,

I’m looking for some advice on how to tackle a particular use case I have. I have two Algolia indexes: Categories and Posts.

Any logged in user of my app should be able to search the entire Categories index: this can be achieved using the Search API key that comes by default and all works okay.

The Posts index I want to secure by ensuring that the logged in user can search only their own posts, not the entire index. To do this I added a userId property to the index and generated a secureAPIKey with the filter attribute set:

const publicKey = client.generateSecuredApiKey(SEARCH_KEY, { filters:userId:${userId} });

The problem I have now is that the filter is also applied to the Categories index, which I verified by making a Postman request:

{

    "hits": [],
    "nbHits": 0,
    "page": 0,
    "nbPages": 0,
    "hitsPerPage": 20,
    "exhaustiveNbHits": true,
    "query": "spa",
    "params": "query=spa&filters=userId%3Ai3wd8zL3seV0bDhhYSCZecSs9jK2",
    "processingTimeMS": 1

}

So my question is: how should approach allowing unrestricted search to one set of indices, but restricted search to another set, using only one API Key? (I assume I shouldn’t be generating keys specifically per index, they should be per user/user session?)

Many thanks,

Hello Matt,

Technically speaking, if you need two different access levels per index, you’ll need to use two different API keys depending on what index you’re searching into. In your case, you can have both the default search API key and the secured API returned from your back end stored in your app, and use either depending on the index being search.

However, if you’re using one of our InstantSearch libraries, this solution will likely be cumbersome because you’ll have to keep two instances, build your UI yourself and forward the state to both instances. Definitely not ideal.

What we recommend is tweaking the filter you have in your secured API key:

const publicKey = client.generateSecuredApiKey(SEARCH_KEY, {
  filters: `userId:${userId} OR userId:false`, // Don't use `null` instead, as Algolia can't search `null` or missing values.
});

Then, in your Categories index (which is open), you can set an attribute userId to false in each record. In your Posts index (which is restricted), userId will always be set to a specific user ID, so the secured API key will always retrieve all matching Categories records and all matching Posts records that also have the authorized ID.

On a side note, you said that your Categories index is available to all logged in users, which means it shouldn’t be allowed to anonymous users, is that correct? If yes, then I would recommend using a secured API key here too, to ensure that nobody but your logged in users can search this index.

You can add another attribute (e.g., loggedIn:true) to all your records in both indices, and tweak your secured API key some more:

const publicKey = client.generateSecuredApiKey(SEARCH_KEY, {
  filters: `loggedIn:true AND (userId:${userId} OR userId:false)`,
});
1 Like

Hi Sarah,

Thank you so much for the detailed response, it really helps and definitely gives me a way forward. I appreciate it!

1 Like