"""AWS Secrets Manager client for fetching Auth0 tenant credentials.""" import json from dataclasses import dataclass import boto3 @dataclass class TenantCredentials: """Auth0 Management API credentials for a single tenant.""" domain: str client_id: str client_secret: str class SecretsManagerClient: """Fetches Auth0 tenant credentials from AWS Secrets Manager. Secrets follow the naming convention: shared/{tenant_name}/auth0_management_app Each secret is a JSON object with keys: auth0_client_id, auth0_client_secret """ def __init__(self) -> None: """Initialize with a boto3 Secrets Manager client.""" self._client = boto3.client('secretsmanager') _REQUIRED_SECRET_KEYS = {'auth0_domain', 'auth0_client_id', 'auth0_client_secret'} def get_tenant_credentials(self, tenant_name: str) -> TenantCredentials: """Retrieve Auth0 credentials for the given tenant. :param tenant_name: Auth0 tenant name (e.g. 'my-tenant') :return: TenantCredentials with domain, client_id, and client_secret :raises ValueError: If the secret is missing required keys. """ secret_name = ( f'shared/offboarding-automation/{tenant_name}/auth0_management_credentials' ) response = self._client.get_secret_value(SecretId=secret_name) secret = json.loads(response['SecretString']) missing = self._REQUIRED_SECRET_KEYS - set(secret.keys()) if missing: raise ValueError( f'Secret for tenant {tenant_name!r} is missing keys: {sorted(missing)}' ) return TenantCredentials( domain=secret['auth0_domain'], client_id=secret['auth0_client_id'], client_secret=secret['auth0_client_secret'], )