I have a Flutter based app where I"m trying to mak...
# community-help
s
I have a Flutter based app where I"m trying to make scope search API keys work, but i don't think that the official Typesense lib supports it. Do i need to call HTTP direct instead of using this lib if i want this security feature? https://pub.dev/packages/typesense
I add the scoped search key where the normal apiKey goes, but get a 401
Copy code
401: {"message": "Forbidden - a valid `x-typesense-api-key` header must be sent."}
Code block
Copy code
Future<Configuration> getTypeSenseConfig(Environment environment) async {
    final typeSenseConfig = TypeSenseConfig(environment);

    var generatedScopeKey =
        await callGenerateScopedSearchKey('userId', 'accountId');

    // Create and return the Configuration instance
    final config = Configuration(
      generatedScopeKey,
      nodes: {
        Node.withUri(
          Uri(
            scheme: 'https',
            host: typeSenseConfig.typeSenseHost,
            port: 443,
          ),
        ),
      },
      numRetries: 3, // A total of 4 tries (1 original try + 3 retries)
      connectionTimeout: const Duration(seconds: 2),
    );

    return config;
  }
j
The client library is agnostic to scoped api keys - it’s just another api key from the client’s perspective
It’s likely that there’s some filter embedded inside the scoped api key that’s invalid
Could you share the code snippet you’re using to generate the scoped api key?
s
this code is in a Cloud Function and is called by the client to get the search key. this will successfully return a key.
Copy code
// @ts-check
const Typesense = require("typesense");

// Initialize Typesense client
const typesenseClient = new Typesense.Client({
  // Set the appropriate endpoint and API key for your Typesense instance
  nodes: [
    {
      host: "<http://redacted-1.a1.typesense.net|redacted-1.a1.typesense.net>",
      port: 443,
      protocol: "https", // Use 'https' for secure connection
    },
  ],
  apiKey: "redacted",
});

// Function to generate a scoped search key
async function generateScopedSearchKeyForTypesense(userId, accountId) {
  try {
    // Make sure that the parent search key you use to generate a scoped search key
    //  has no other permissions besides `documents:search`

    // Generate a scoped search API key with embedded filter
    const searchKey = "redacted"; // Replace with your main search API key
    const parameters = {
      filter_by: `accountId:=${accountId}`,
    };
    const scopedSearchKey = await typesenseClient.keys().generateScopedSearchKey(searchKey, parameters);

    // Make sure that the parent search key you use to generate a scoped search key
    //  has no other permissions besides `documents:search`

    // Return the scoped search key
    return scopedSearchKey;
  } catch (error) {
    console.error("Error generating scoped search key:", error);
    throw error;
  }
}

module.exports = generateScopedSearchKeyForTypesense;
j
This comment is the solution:
Copy code
// Make sure that the parent search key you use to generate a scoped search key
//  has no other permissions besides `documents:search`
It looks like all your API keys have this as the permission:
Copy code
[ "documents:search", "documents:get" ]
You want to create separate API keys to use with a scoped search api key and the search endpoint (with just the
documents:search
permission), vs the documents:get endpoint
s
so generate a new api search key that ONLY has documents:search. Okay, i'll try that. thanks
👍 1
you are a wise man, yes that worked! I'm getting this error now, however i'm wondering the best way to generate this:
400: {"message": "No search fields specified for the query."}
I'm using that cloud function in order to generate the scope searched key with the only required parameter (for security purposes) that is required and that is
accountId
. I'm taking that scoped security key and using it in my Configuration object from Flutter. Then I'm querying with what the user would be searching. Maybe i move this all to the server side cloud function?
Copy code
final searchParameters = {
      'q': searchModel
          .searchKey, // Access searchKey property using the null-aware operator
      'per_page': pageSize.toString(),
      'page': (pageKey + 1).toString(),
      'preset': 'inventory_search',
      'filter_by': filterBy,
      "sort_by": "modifiedOn:desc",
      'facet_by': 'category,status',
    };
j
You also want to specify the query_by field in the search parameters
s
This message contains interactive elements.
j
Oh you’re right - I missed the
preset
param in your code snippet above. My bad.
Could you give me a curl command that replicates the HTTP 400, with all the search params?
s
yes, give me a few
so it looks like it wants to
q
parameter, but the purpose of this function is get my search scope key, and then call the actual search with that key and a query. is that how it's supposed to work?
j
the purpose of this function is get my search scope key
You would use the code in this function to get your search scoped key
And then use that scoped API key to make this search API call