From 6409ce3c9e37c05e01ba9c7625cd7d8e106afa81 Mon Sep 17 00:00:00 2001 From: Erik Peterson Date: Wed, 8 Apr 2026 16:20:31 -0700 Subject: [PATCH] feat: support file path for OKTA_PRIVATE_KEY Allow OKTA_PRIVATE_KEY to accept either inline PEM content or a path to a PEM file on disk. If the value is a valid file path, the key is read from the file; otherwise, it is used as-is (with escaped newline handling preserved for inline values). --- .env.example | 2 ++ src/okta_mcp_server/utils/auth/auth_manager.py | 15 +++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index 6770e88..c02d5f2 100644 --- a/.env.example +++ b/.env.example @@ -12,6 +12,8 @@ OKTA_SCOPES=okta.users.read okta.groups.read # Optional: For Private Key JWT authentication (browserless) # Uncomment and set these if using Private Key JWT instead of Device Authorization +# OKTA_PRIVATE_KEY can be either the PEM content directly or a path to a PEM file +# OKTA_PRIVATE_KEY=/path/to/private_key.pem # OKTA_PRIVATE_KEY= # OKTA_KEY_ID= diff --git a/src/okta_mcp_server/utils/auth/auth_manager.py b/src/okta_mcp_server/utils/auth/auth_manager.py index 2dcdceb..8be755f 100644 --- a/src/okta_mcp_server/utils/auth/auth_manager.py +++ b/src/okta_mcp_server/utils/auth/auth_manager.py @@ -45,15 +45,22 @@ def __init__(self): self.scopes = f"{self.scopes} {os.environ.get('OKTA_SCOPES', '').strip()}" # Check for browserless auth configuration - self.private_key = os.environ.get("OKTA_PRIVATE_KEY") + private_key_value = os.environ.get("OKTA_PRIVATE_KEY") self.key_id = os.environ.get("OKTA_KEY_ID") + if private_key_value and os.path.isfile(private_key_value): + logger.info(f"Loading private key from file: {private_key_value}") + with open(private_key_value) as f: + self.private_key = f.read() + else: + self.private_key = private_key_value + # Process private key if it contains escaped newlines + if self.private_key and "\\n" in self.private_key: + self.private_key = self.private_key.replace("\\n", "\n") + if self.private_key and self.key_id: self.use_browserless_auth = True logger.info("Browserless authentication is available and will be used") - # Process private key if it contains escaped newlines - if "\\n" in self.private_key: - self.private_key = self.private_key.replace("\\n", "\n") else: if self.private_key and not self.key_id: logger.warning("Private key found but OKTA_KEY_ID is missing. Using device flow instead.")