Skip to main content
Glama
auth_box_api.py8.48 kB
import json import pathlib from textwrap import dedent from box_sdk_gen import ( BoxCCGAuth, BoxClient, BoxJWTAuth, BoxOAuth, CCGConfig, FileWithInMemoryCacheTokenStorage, JWTConfig, OAuthConfig, ) from config import BoxApiConfig def get_oauth_config(config: "BoxApiConfig") -> OAuthConfig: """ Get OAuth configuration from the provided config object. Args: config: BoxApiConfig containing client_id and client_secret Returns: OAuthConfig: Configured OAuth settings Raises: ValueError: If required credentials are missing """ if not config.client_id or not config.client_secret: raise ValueError( dedent(""" To use OAUTH authentication, your .env file must contain the following variables: BOX_CLIENT_ID = BOX_CLIENT_SECRET = BOX_REDIRECT_URL = <redirect url as configured in the Box app settings. For MCP Server callback use http://localhost:8000/callback> """) ) return OAuthConfig( client_id=config.client_id, client_secret=config.client_secret, token_storage=FileWithInMemoryCacheTokenStorage(".auth.oauth"), ) def get_oauth_client(config: "BoxApiConfig") -> BoxClient: """ Get OAuth authenticated Box client. Args: config: BoxApiConfig containing OAuth credentials Returns: BoxClient: Authenticated Box client """ conf = get_oauth_config(config) auth = BoxOAuth(conf) return add_extra_header_to_box_client(BoxClient(auth)) def get_ccg_config(config: "BoxApiConfig") -> CCGConfig: """ Get CCG (Client Credentials Grant) configuration from the provided config object. Args: config: BoxApiConfig containing CCG credentials Returns: CCGConfig: Configured CCG settings Raises: ValueError: If required credentials are missing """ if not config.client_id or not config.client_secret or not config.subject_type or not config.subject_id: raise ValueError( dedent(""" To use CCG authentication, your .env file must contain the following variables: BOX_CLIENT_ID = BOX_CLIENT_SECRET = BOX_SUBJECT_TYPE = <enterprise or user> BOX_SUBJECT_ID = <enterprise id or user id> """) ) if config.subject_type == "enterprise": enterprise_id = config.subject_id user_id = None else: enterprise_id = None user_id = config.subject_id return CCGConfig( client_id=config.client_id, client_secret=config.client_secret, enterprise_id=enterprise_id, user_id=user_id, token_storage=FileWithInMemoryCacheTokenStorage( f".auth.ccg.{config.subject_type}.{config.subject_id}" ), ) def get_ccg_client(config: "BoxApiConfig") -> BoxClient: """ Get CCG authenticated Box client. Args: config: BoxApiConfig containing CCG credentials Returns: BoxClient: Authenticated Box client """ conf = get_ccg_config(config) auth = BoxCCGAuth(conf) return add_extra_header_to_box_client(BoxClient(auth)) def get_jwt_config(config: "BoxApiConfig") -> JWTConfig: """ Get JWT configuration from config object. Uses file-based config if jwt_config_file is set, otherwise uses environment variables. Args: config: BoxApiConfig containing JWT credentials Returns: JWTConfig: Configured JWT settings Raises: ValueError: If required credentials are missing """ if config.jwt_config_file: return get_jwt_config_from_file(config) else: return get_jwt_config_from_env(config) def get_jwt_config_from_env(config: "BoxApiConfig") -> JWTConfig: """ Get JWT configuration from environment variables via config object. Args: config: BoxApiConfig containing JWT credentials from environment Returns: JWTConfig: Configured JWT settings Raises: ValueError: If required credentials are missing """ # Validate required variables if ( not config.client_id or not config.client_secret or not config.public_key_id or not config.private_key or not config.private_key_passphrase or not config.subject_type or not config.subject_id ): raise ValueError( dedent(""" To use JWT authentication, your .env file must contain the following variables: BOX_CLIENT_ID = BOX_CLIENT_SECRET = BOX_PUBLIC_KEY_ID = BOX_PRIVATE_KEY = BOX_PRIVATE_KEY_PASSPHRASE = BOX_SUBJECT_TYPE = <enterprise or user> BOX_SUBJECT_ID = <enterprise id or user id> """) ) if config.subject_type == "user": enterprise_id = None user_id = config.subject_id else: enterprise_id = config.subject_id user_id = None return JWTConfig( client_id=config.client_id, client_secret=config.client_secret, jwt_key_id=config.public_key_id, private_key=config.private_key, private_key_passphrase=config.private_key_passphrase, enterprise_id=enterprise_id, user_id=user_id, token_storage=FileWithInMemoryCacheTokenStorage( f".auth.jwt.{config.subject_type}.{config.subject_id}" ), ) def get_jwt_config_from_file(config: "BoxApiConfig") -> JWTConfig: """ Get JWT configuration from a config file. Args: config: BoxApiConfig containing jwt_config_file path and optional subject settings Returns: JWTConfig: Configured JWT settings Raises: ValueError: If config file is missing or invalid """ if not config.jwt_config_file: raise ValueError( dedent(""" To use JWT authentication from a config file, your .env file must contain the following variables: BOX_JWT_CONFIG_FILE = <path to config file> BOX_SUBJECT_TYPE = <enterprise or user> BOX_SUBJECT_ID = <enterprise id or user id> """) ) file_location = pathlib.Path(config.jwt_config_file) if not file_location.is_file(): raise ValueError( f"BOX_JWT_CONFIG_FILE path is not a valid file: {file_location}" ) # Load json file with open(file_location, "r") as f: jwt_file_config = json.load(f) # Use provided subject_type or default to "enterprise" subject_type = config.subject_type if config.subject_type else "enterprise" # Use provided subject_id or get from config file subject_id = config.subject_id if config.subject_id else jwt_file_config.get("enterpriseID") jwt_config = JWTConfig.from_config_json_string( config_json_string=json.dumps(jwt_file_config), token_storage=FileWithInMemoryCacheTokenStorage( f".auth.jwt.{subject_type}.{subject_id}" ), ) # check if we have user_id or enterprise_id set if subject_type == "user": jwt_config.user_id = subject_id jwt_config.enterprise_id = None else: jwt_config.enterprise_id = subject_id jwt_config.user_id = None return jwt_config def get_jwt_client(config: "BoxApiConfig") -> BoxClient: """ Get JWT authenticated Box client. Args: config: BoxApiConfig containing JWT credentials Returns: BoxClient: Authenticated Box client """ conf = get_jwt_config(config) auth = BoxJWTAuth(conf) # Box API does not seem to recognize the JWT client with user vs enterprise set # refreshing the token seems to fix this issue auth.refresh_token() return add_extra_header_to_box_client(BoxClient(auth)) def add_extra_header_to_box_client(box_client: BoxClient) -> BoxClient: """ Add extra headers to the Box client. Args: box_client (BoxClient): A Box client object. header (Dict[str, str]): A dictionary of extra headers to add to the Box client. Returns: BoxClient: A Box client object with the extra headers added. """ header = {"x-box-ai-library": "mcp-server-box"} return box_client.with_extra_headers(extra_headers=header)

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/box-community/mcp-server-box'

If you have feedback or need assistance with the MCP directory API, please join our Discord server