diff --git a/.gitignore b/.gitignore
index e8bf92ead3e777406d4d7eeb484af7b7bfb557ad..33b68146aa9a024e14107b02d40c194a884ca0f2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,5 +10,6 @@ coverage.xml
 htmlcov
 dist
 venv
+.venv
 .vscode
 docs/build
diff --git a/docs/source/configuration.rst b/docs/source/configuration.rst
index 3502d074966387065a92af957caaae1a22c2aacd..28b30adfb9cf32669953e9562676164001524a1f 100644
--- a/docs/source/configuration.rst
+++ b/docs/source/configuration.rst
@@ -54,7 +54,7 @@ This module has been tested in the following execution environments:
   .. code-block:: bash
 
      $ export FLASK_APP=app.py
-     $ export SETTINGS_FILENAME=settings.cfg
+     $ export FLASK_SETTINGS_FILENAME=settings.cfg
      $ flask run
 
 * As an Apache/`mod_wsgi` service.
diff --git a/inventory_provider/__init__.py b/inventory_provider/__init__.py
index 09574fb6f842e27db80a60b3fd47de92d4b2e91b..3155d6cce97b98ca09e7942da6806f23292a2181 100644
--- a/inventory_provider/__init__.py
+++ b/inventory_provider/__init__.py
@@ -7,6 +7,7 @@ from flask import Flask
 from flask_cors import CORS
 
 from inventory_provider import environment
+from inventory_provider.auth import auth
 
 
 def create_app(setup_logging=True):
@@ -48,6 +49,13 @@ def create_app(setup_logging=True):
 
     app.config['INVENTORY_PROVIDER_CONFIG'] = inventory_provider_config
 
+    # Apply authentication globally to all routes
+    @app.before_request
+    @auth.login_required
+    def secure_before_request():
+        # This method is a boilerplate required by the library to enable authentication
+        pass
+
     # IMS based routes
 
     from inventory_provider.routes import lg
diff --git a/inventory_provider/auth.py b/inventory_provider/auth.py
new file mode 100644
index 0000000000000000000000000000000000000000..1dd8ff81ef56049673223f08c3e1f327376ee8a8
--- /dev/null
+++ b/inventory_provider/auth.py
@@ -0,0 +1,39 @@
+from functools import wraps
+from flask import current_app, g, jsonify
+from flask_httpauth import HTTPTokenAuth
+
+from inventory_provider.config import ANONYMOUS_SERVICE_NAME
+
+auth = HTTPTokenAuth(scheme="ApiKey")
+
+@auth.verify_token
+def verify_api_key(api_key):
+    config = current_app.config["INVENTORY_PROVIDER_CONFIG"]
+    # This is to enable anonymous access for testing.
+    if not api_key:
+        g.auth_client = ANONYMOUS_SERVICE_NAME
+        return ANONYMOUS_SERVICE_NAME
+
+    for client, details in config['api-keys'].items():
+        if details.get('api-key') == api_key:
+            g.auth_client = client
+            return client
+    return None
+
+def authorize(*, allowed_clients):
+    """Decorator to restrict route access to specific clients."""
+    if not isinstance(allowed_clients, list):
+        raise TypeError("allowed_clients must be a list of allowed service names")
+
+    def decorator(f):
+        @wraps(f)
+        def wrapped(*args, **kwargs):
+            client = g.get("auth_client")
+            if client not in allowed_clients:
+                # Anonymous clients are allowed to access any resource without providing an API key
+                # TODO: Only for testing, should be removed in Production
+                if client != ANONYMOUS_SERVICE_NAME:
+                    return jsonify({"error": "Forbidden"}), 403
+            return f(*args, **kwargs)
+        return wrapped
+    return decorator
diff --git a/inventory_provider/config.py b/inventory_provider/config.py
index 3fa03b9de584b4783a4305ad9f4e9ee7ec014ba3..c8497a8bc03c1e2cc225a772fe450582bed98467 100644
--- a/inventory_provider/config.py
+++ b/inventory_provider/config.py
@@ -1,6 +1,11 @@
 import json
 import jsonschema
 
+DASHBOARD_SERVICE_NAME = 'dashboard'
+BRIAN_SERVICE_NAME = 'brian'
+REPORTING_SERVICE_NAME = 'reporting'
+ANONYMOUS_SERVICE_NAME = 'anonymous'
+
 CONFIG_SCHEMA = {
     '$schema': 'https://json-schema.org/draft-07/schema#',
 
@@ -10,6 +15,23 @@ CONFIG_SCHEMA = {
             'maximum': 60,  # sanity
             'exclusiveMinimum': 0
         },
+        'api-key': {
+            "type": "object",
+            "properties": {
+                "api-key": {"type": "string"}
+            },
+            "required": ["api-key"],
+            "additionalProperties": False
+        },
+        "api-keys-credentials": {
+            "type": "object",
+            'properties': {
+                DASHBOARD_SERVICE_NAME: {'$ref': '#/definitions/api-key'},
+                BRIAN_SERVICE_NAME: {'$ref': '#/definitions/api-key'},
+                REPORTING_SERVICE_NAME: {'$ref': '#/definitions/api-key'}
+            },
+            "additionalProperties": False
+        },
         'ssh-credentials': {
             'type': 'object',
             'properties': {
@@ -235,6 +257,7 @@ CONFIG_SCHEMA = {
 
     'type': 'object',
     'properties': {
+        'api-keys': {'$ref': '#/definitions/api-keys-credentials'},
         'ssh': {'$ref': '#/definitions/ssh-credentials'},
         'nokia-ssh': {'$ref': '#/definitions/nokia-ssh-credentials'},
         'redis': {'$ref': '#/definitions/redis-credentials'},
diff --git a/inventory_provider/routes/classifier.py b/inventory_provider/routes/classifier.py
index 47c4e888d3c4d40b85a6f424c597534fcc972b29..018df7f53f12ef9372bf56e92ae0af0b26ca5288 100644
--- a/inventory_provider/routes/classifier.py
+++ b/inventory_provider/routes/classifier.py
@@ -67,6 +67,9 @@ from redis import Redis
 from inventory_provider.routes import common
 from inventory_provider.routes.common import _ignore_cache_or_retrieve, cache_result
 
+from inventory_provider.auth import authorize
+from inventory_provider.config import DASHBOARD_SERVICE_NAME
+
 routes = Blueprint("inventory-data-classifier-support-routes", __name__)
 
 logger = logging.getLogger(__name__)
@@ -331,6 +334,7 @@ def get_link_info_response_body(
 @routes.route("/juniper-link-info/<source_equipment>/<path:interface>",
               methods=['GET'])
 @common.require_accepts_json
+@authorize(allowed_clients=[DASHBOARD_SERVICE_NAME])
 def handle_link_info_request(source_equipment: str, interface: str) -> Response:
     """
     Handler for /classifier/juniper-link-info that
@@ -372,6 +376,7 @@ def handle_link_info_request(source_equipment: str, interface: str) -> Response:
 
 @routes.route("/epipe-sap-info/<source_equipment>/<service_id>/<vpn_id>", methods=['GET'])
 @common.require_accepts_json
+@authorize(allowed_clients=[DASHBOARD_SERVICE_NAME])
 def handle_epipe_sap_info_request(source_equipment: str, service_id: str, vpn_id: str) -> Response:
 
     r = common.get_current_redis()
@@ -600,6 +605,7 @@ def find_interfaces(address):
 
 @routes.route("/peer-info/<address_str>", methods=['GET'])
 @common.require_accepts_json
+@authorize(allowed_clients=[DASHBOARD_SERVICE_NAME])
 def peer_info(address_str: str) -> Response:
     """
     Handler for /classifier/peer-info that returns bgp peering metadata.
@@ -695,6 +701,7 @@ def peer_info(address_str: str) -> Response:
 @routes.route(
     "/mtc-interface-info/<node>/<interface>", methods=['GET'])
 @common.require_accepts_json
+@authorize(allowed_clients=[DASHBOARD_SERVICE_NAME])
 def get_mtc_interface_info(node, interface):
     """
     Handler for /classifier/mtc-interface-info that
@@ -736,6 +743,7 @@ def get_mtc_interface_info(node, interface):
               "<source_equipment>/<interface>/<circuit_id>",
               methods=['GET'])
 @common.require_accepts_json
+@authorize(allowed_clients=[DASHBOARD_SERVICE_NAME])
 def get_trap_metadata(source_equipment: str, interface: str, circuit_id: str) \
         -> Response:
     """
@@ -829,6 +837,7 @@ def get_trap_metadata(source_equipment: str, interface: str, circuit_id: str) \
 @routes.route("/infinera-fiberlink-info/<ne_name_str>/<object_name_str>",
               methods=['GET'])
 @common.require_accepts_json
+@authorize(allowed_clients=[DASHBOARD_SERVICE_NAME])
 def get_fiberlink_trap_metadata(ne_name_str: str, object_name_str: str) \
         -> Response:
     """
@@ -965,6 +974,7 @@ def get_fiberlink_trap_metadata(ne_name_str: str, object_name_str: str) \
 
 @routes.route("/tnms-fibre-info/<path:enms_pc_name>", methods=['GET'])
 @common.require_accepts_json
+@authorize(allowed_clients=[DASHBOARD_SERVICE_NAME])
 def get_tnms_fibre_trap_metadata(enms_pc_name: str) -> Response:
     """
     Handler for /classifier/infinera-fiberlink-info that
@@ -1067,6 +1077,7 @@ def get_tnms_fibre_trap_metadata(enms_pc_name: str) -> Response:
 @routes.route('/coriant-port-info/<equipment_name>/<path:entity_string>',
               methods=['GET'])
 @common.require_accepts_json
+@authorize(allowed_clients=[DASHBOARD_SERVICE_NAME])
 def get_coriant_port_info(equipment_name: str, entity_string: str) -> Response:
     """
     Handler for /classifier/coriant-info that
@@ -1088,6 +1099,7 @@ def get_coriant_port_info(equipment_name: str, entity_string: str) -> Response:
 @routes.route('/coriant-tp-info/<equipment_name>/<path:entity_string>',
               methods=['GET'])
 @common.require_accepts_json
+@authorize(allowed_clients=[DASHBOARD_SERVICE_NAME])
 def get_coriant_tp_info(equipment_name: str, entity_string: str) -> Response:
     """
     Handler for /classifier/coriant-info that
@@ -1198,6 +1210,7 @@ def _get_coriant_info(
 
 @routes.route("/router-info", methods=["GET"])
 @common.require_accepts_json
+@authorize(allowed_clients=[DASHBOARD_SERVICE_NAME])
 def get_all_routers() -> Response:
     redis = common.get_current_redis()
     result = cache_result(
@@ -1220,6 +1233,7 @@ def _get_router_list(redis):
 
 @routes.route("/router-info/<equipment_name>", methods=["GET"])
 @common.require_accepts_json
+@authorize(allowed_clients=[DASHBOARD_SERVICE_NAME])
 def get_router_info(equipment_name: str) -> Response:
     redis = common.get_current_redis()
     ims_equipment_name = get_ims_equipment_name_or_none(equipment_name, redis)
diff --git a/requirements.txt b/requirements.txt
index 0d226651b91236f8b7bd716d444d6d71eb3c1d0a..9095eb74b7d4b98f3f86a727cbb003ab23ba72f9 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -16,6 +16,7 @@ lxml==4.9.4
 requests
 netifaces
 tree-format
+Flask-HTTPAuth
 
 pytest
 pytest-mock
diff --git a/test/conftest.py b/test/conftest.py
index 1c276b4c89fe5deec9bf787715799dd3b076d160..354126826574b8ce6c4227c458b0a22322429e29 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -70,6 +70,17 @@ def data_config_filename():
 
     with tempfile.NamedTemporaryFile() as f:
         config = {
+            "api-keys": {
+                "brian": {
+                    "api-key": "brian_key"
+                },
+                "dashboard": {
+                    "api-key": "dashboard_key"
+                },
+                "reporting": {
+                    "api-key": "reporting_key"
+                },
+            },
             "ssh": {
                 "username": "uSeR-NaMe",
                 "private-key": "private-key-filename",
diff --git a/test/test_auth.py b/test/test_auth.py
new file mode 100644
index 0000000000000000000000000000000000000000..226ab7a5009b2df1dd187ef14bafca01c276c7d2
--- /dev/null
+++ b/test/test_auth.py
@@ -0,0 +1,75 @@
+import jsonschema
+
+from inventory_provider.routes.classifier_schema import (
+    ROUTER_INFO_ALL_ROUTERS_RESPONSE_SCHEMA,
+)
+
+DEFAULT_REQUEST_HEADERS_NO_KEY = {
+    "Content-type": "application/json",
+    "Accept": ["application/json"],
+}
+
+DEFAULT_REQUEST_HEADERS_BRIAN_KEY = {
+    "Content-type": "application/json",
+    "Accept": ["application/json"],
+    "Authorization": "ApiKey brian_key",
+}
+
+DEFAULT_REQUEST_HEADERS_REPORTING_KEY = {
+    "Content-type": "application/json",
+    "Accept": ["application/json"],
+    "Authorization": "ApiKey reporting_key",
+}
+
+DEFAULT_REQUEST_HEADERS_DASHBOARD_KEY = {
+    "Content-type": "application/json",
+    "Accept": ["application/json"],
+    "Authorization": "ApiKey dashboard_key",
+}
+
+DEFAULT_REQUEST_HEADERS_BAD_KEY = {
+    "Content-type": "application/json",
+    "Accept": ["application/json"],
+    "Authorization": "ApiKey badapikey",
+}
+
+def test_classifier_router_no_key(client):
+    rv = client.get("/classifier/router-info", headers=DEFAULT_REQUEST_HEADERS_NO_KEY)
+    assert rv.status_code == 200
+    assert rv.is_json
+    result = rv.json
+
+    jsonschema.validate(result, ROUTER_INFO_ALL_ROUTERS_RESPONSE_SCHEMA)
+    assert len(result) > 0
+
+def test_classifier_router_dashboard_key(client):
+    rv = client.get("/classifier/router-info", headers=DEFAULT_REQUEST_HEADERS_DASHBOARD_KEY)
+    assert rv.status_code == 200
+    assert rv.is_json
+    result = rv.json
+
+    jsonschema.validate(result, ROUTER_INFO_ALL_ROUTERS_RESPONSE_SCHEMA)
+    assert len(result) > 0
+
+def test_classifier_router_brian_key(client):
+    rv = client.get("/classifier/router-info", headers=DEFAULT_REQUEST_HEADERS_BRIAN_KEY)
+    assert rv.status_code == 403
+    assert rv.is_json
+    result = rv.json
+
+    assert result["error"] == "Forbidden"
+
+def test_classifier_router_reporting_key(client):
+    rv = client.get("/classifier/router-info", headers=DEFAULT_REQUEST_HEADERS_REPORTING_KEY)
+    assert rv.status_code == 403
+    assert rv.is_json
+    result = rv.json
+
+    assert result["error"] == "Forbidden"
+
+def test_classifier_router_bad_key(client):
+    rv = client.get("/classifier/router-info", headers=DEFAULT_REQUEST_HEADERS_BAD_KEY)
+    assert rv.status_code == 401
+    result = rv.text
+
+    assert result == "Unauthorized Access"
diff --git a/test/test_flask_config.py b/test/test_flask_config.py
index 7ba83ec54c3e2e8389924e14b3cff0bad6aea29b..48f7e29c2ab998319c33894d7f11a27efe737449 100644
--- a/test/test_flask_config.py
+++ b/test/test_flask_config.py
@@ -7,6 +7,17 @@ from inventory_provider.config import CONFIG_SCHEMA
 @pytest.fixture
 def config():
     return {
+        "api-keys": {
+            "brian": {
+                "api-key": "brian_key"
+            },
+            "dashboard": {
+                "api-key": "dashboard_key"
+            },
+            "reporting": {
+                "api-key": "reporting_key"
+            },
+        },
         'redis': {
             'hostname': 'localhost',
             'port': 6379,