Skip to content

BUG: Empty OAuth endpoint paths concatenate as "null" string #1970

@tegge

Description

@tegge

Description

Current Behavior:
When auth_code_endpoint or access_token_endpoint are empty strings in globalConfig.json,
UCC generates code that stringifies them as "null" in OAuth URLs.
Example:

  • Config: "auth_code_endpoint": ""
  • Generated URL: https://oauth.provider.com/oauth/authorizenull?...
  • Expected URL: https://oauth.provider.com/oauth/authorize?...

Root Causes:
Python:

JavaScript: https://github.com/splunk/addonfactory-ucc-generator/blob/1b02b4fc5587d83176c7bcf818b8ccf619c392aa/ui/src/components/BaseFormView/BaseFormView.tsx#L365C1-L368C85

  1. Using || instead of ?? causes empty string coercion
  2. No validation that paths are paths (not full URLs)
  3. String concatenation instead of URL construction APIs

Proposed Fixes:

  1. Use nullish coalescing (??) to preserve null semantics
  2. Add validation: paths must start with /, cannot contain ://
  3. Use URL constructor (JS) and urlunsplit (Python) for safe URL building
  4. Throw explicit errors on invalid configuration

Python example

def normalize_oauth_endpoint_path(maybe_path: Optional[str]) -> str:
    """
    Normalizes OAuth endpoint path with validation.
    
    Args:
        maybe_path: The endpoint path (can be None or string)
        
    Returns:
        Normalized path string (empty if None)
        
    Raises:
        ValueError: If path is invalid
        TypeError: If path is not a string
    """
    # None or empty → no path
    if not maybe_path:
        return ""
    
    if not isinstance(maybe_path, str):
        raise TypeError("OAuth endpoint must be a string")
    
    # Validate: must be a path, not a full URL
    if "://" in maybe_path:
        raise ValueError(
            "OAuth endpoint must be a path (e.g., '/oauth/token'), not a full URL"
        )
    
    # Validate: prevent protocol-relative URLs
    if maybe_path.startswith("//"):
        raise ValueError("Protocol-relative URLs not allowed in OAuth endpoint")
    
    # Ensure leading slash for proper URL construction
    return maybe_path if maybe_path.startswith("/") else f"/{maybe_path}"
def build_oauth_url(host: str, endpoint_path: Optional[str]) -> str:
    """
    Build OAuth URL from host and optional path.
    
    Args:
        host: The host (e.g., 'accounts.google.com' or '127.0.0.1:5001')
        endpoint_path: Optional path component
        
    Returns:
        Complete HTTPS URL
    """
    path = normalize_oauth_endpoint_path(endpoint_path)
    return urlunsplit(("https", host, path, "", ""))

In the oauth helper:

    TOKEN_ENDPOINT = self.oauth_conf_mgr.get_oauth_spec(conf_type).get(
        "access_token_endpoint"
    )
    # TOKEN_ENDPOINT is None if absent, string if present
    return build_oauth_url(host, TOKEN_ENDPOINT)
except (ValueError, TypeError) as e:
    raise ValueError(f"Invalid OAuth token endpoint configuration: {e}")

For javascript you could make two functions one to normalize to null and one specifically to interpret any absence or empty string to "" for the url concatenation.

Benefits:

  • Prevents "null" stringification
  • Prevents absolute URL injection in path fields
  • Clear error messages for misconfiguration
  • Maintains semantic distinction: null = absent, "" = empty path

Use Case:
Allows users to specify full OAuth endpoint URLs in the endpoint field when
paths are non-standard or when endpoint differs between authorization/token #

What UCC version are you using?

splunk-add-on-ucc-framework==6.1.0

Additional System Info

Python 3.13.1, MacOS 26.2, Splunk 9.4

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingtriagePending triage from maintainers

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions