Query Parameter ApiKey

This example modifies the out-of-the-box AuthApiKey authenticator to send an API key as a query parameter instead of in a header key. The code for the AuthApiKey is shown below with the highlighted text that will be changed:

 1from silo.auth import Authenticator, add_auth, http_check_result
 2
 3@add_auth
 4class AuthApiKey(Authenticator):
 5    def __init__(self, credentials):
 6        """Constructor method"""
 7        Authenticator.__init__(self, credentials)
 8        self.token_label = credentials.fields.get("auth_header", "Authorization")
 9        self.prefix = credentials.fields.get("prefix", "")
10        self.suffix = credentials.fields.get("suffix", "")
11        self.apikey = credentials.fields["apikey"]
12        self.auth_info = {}
13        self.cred_filter = CredentialFilter(credentials)
14
15    def check_if_authenticated(self):
16        """Returns the current authentication status."""
17        return False
18
19    def check_result(self, result):
20        """Provides a check on the returned response from the REST request that was made."""
21        return http_check_result(result)
22
23    def authenticate(self):
24        """Updates the auth_info with the ApiKey/Token using the credentials provided.
25
26        :return: If the auth_info is updated, return True, else return False
27        :rtype: boolean
28        """
29        ""
30        formatted_apikey = "{} {} {}".format(self.prefix, self.apikey, self.suffix).strip()
31        self.auth_info[self.token_label] = formatted_apikey
32        self.cred_filter.update_secret(self.token_label, formatted_apikey)
33        return True
34
35    def modify_request(self, res):
36        """Modifies a requests.Session headers or query_params to contain the updated
37        auth_info for a resource.
38
39        :param requests.Session res: a Session object
40
41        :return: If the session is authenticated, return True, else return False
42        :rtype: boolean
43        """
44        self.authenticate()
45        res.headers.update(self.auth_info)
46        return True
47
48    @staticmethod
49    def build(credentials, *args, **kwargs):
50        """Build method to be called by get_authmethod in Snippet Framework"""
51        return AuthApiKey(credentials)
52
53    @staticmethod
54    def get_name():
55        """Returns the name of the authentication method"""
56        return "AuthApiKey"
57
58    @staticmethod
59    def get_desc():
60        """Returns a description of the authentication method"""
61        return "ApiKey Authentication for HTTP"

Line 32 will be modified such that the apikey is stored in query parameters versus the header. res.headers.update(self.auth_info) is changed to res.params.update(self.auth_info).

Our new authenticator looks like the following:

from silo.auth import add_auth, AuthApiKey

@add_auth
class AuthApiKeyQuery(AuthApiKey):
    def __init__(self, credentials, **kwargs):
        """Constructor method"""
        AuthApiKey.__init__(self, credentials, **kwargs)

    def modify_request(self, res):
        """Modifies a requests.Session query_params to contain the updated
        auth_info for a resource.

        :param requests.Session res: a Session object

        :return: True
        :rtype: boolean
        """
        self.authenticate()
        res.params.update(self.auth_info)
        return True

    @staticmethod
    def build(credentials, **kwargs):
        """Build method to be called by get_authmethod in Snippet Framework"""
        return AuthApiKeyQuery(credentials, **kwargs)

    @staticmethod
    def get_name():
        """Returns the name of the authentication method"""
        return "AuthApiKeyQuery"

    @staticmethod
    def get_desc():
        """Returns a description of the authentication method"""
        return "AuthApiKeyQuery Authentication for HTTP"

The AuthApiKeyQuery inherits from the existing AuthApiKey authenticator for the token formatting done in authenticate(). The biggest change is in modify_request() where it saves the apikey into the session’s parameters.

Putting It All Together

For a test, we will attempt to access a json payload listing alternative fuel stations. This endpoint accepts the apikey as a query parameter api_key=DEMO_KEY. See Data Gov Dev Manual

Snippet

from silo.auth import add_auth, AuthApiKey

@add_auth
class AuthApiKeyQuery(AuthApiKey):
    def __init__(self, credentials, **kwargs):
        """Constructor method"""
        AuthApiKey.__init__(self, credentials, **kwargs)

    def modify_request(self, res):
        """Modifies a requests.Session query_params to contain the updated
        auth_info for a resource.

        :param requests.Session res: a Session object

        :return: True
        :rtype: boolean
        """
        self.authenticate()
        res.params.update(self.auth_info)
        return True

    @staticmethod
    def build(credentials, **kwargs):
        """Build method to be called by get_authmethod in Snippet Framework"""
        return AuthApiKeyQuery(credentials, **kwargs)

    @staticmethod
    def get_name():
        """Returns the name of the authentication method"""
        return "AuthApiKeyQuery"

    @staticmethod
    def get_desc():
        """Returns a description of the authentication method"""
        return "AuthApiKeyQuery Authentication for HTTP"

Snippet Argument

low_code:
version: 2
steps:
    - http:
        url: https://developer.nrel.gov/api/alt-fuel-stations/v1.json
        params:
            limit: 1
        check_status_code: False
    - json

Credential

../../_images/apikey_query.png

Note

The Authorization Header field is used to define the query parameter which, in this case, must be the expected apikey.