> ## Documentation Index
> Fetch the complete documentation index at: https://www.osohq.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Installation and Setup

> Install and configure the Oso Cloud SDKs.

export const Languages = {
  JAVASCRIPT: "js",
  PYTHON: "py",
  RUBY: "rb",
  JAVA: "java",
  DOTNET: "dotnet",
  GO: "go",
  SHELL: "shell",
  MACOS: "macos",
  WINDOWS: "windows",
  BASH: "bash",
  CMD: "cmd",
  TYPESCRIPT: "ts",
  HTML: "html",
  CSS: "css",
  JSON: "json",
  YAML: "yaml",
  XML: "xml"
};

export const CodeTab = ({title, language, children, disabled = false}) => {
  const getLanguageDisplayName = language => {
    const displayNames = {
      [Languages.JAVASCRIPT]: "JavaScript",
      [Languages.PYTHON]: "Python",
      [Languages.RUBY]: "Ruby",
      [Languages.JAVA]: "Java",
      [Languages.DOTNET]: ".NET",
      [Languages.GO]: "Go",
      [Languages.SHELL]: "Shell",
      [Languages.MACOS]: "MacOS / Linux",
      [Languages.WINDOWS]: "Windows",
      [Languages.CMD]: "Command Prompt",
      [Languages.TYPESCRIPT]: "TypeScript",
      [Languages.HTML]: "HTML",
      [Languages.CSS]: "CSS",
      [Languages.JSON]: "JSON",
      [Languages.YAML]: "YAML",
      [Languages.XML]: "XML"
    };
    return displayNames[language] || language || "Code";
  };
  const displayTitle = title || getLanguageDisplayName(language);
  if (!displayTitle) {
    console.warn('CodeTab component requires either a title prop or language prop');
    return null;
  }
  if (language && typeof language !== 'string') {
    console.warn('CodeTab language prop must be a string');
  }
  if (title && typeof title !== 'string') {
    console.warn('CodeTab title prop must be a string');
  }
  if (disabled && typeof disabled !== 'boolean') {
    console.warn('CodeTab disabled prop must be a boolean');
  }
  return React.createElement(React.Fragment, null, children);
};

export const CodeTabs = ({children, defaultTab = 0, className = '', syncLanguages = true, onTabChange, 'aria-label': ariaLabel = 'Code examples'}) => {
  const {useState, useMemo, useEffect, useCallback, useId, Children, isValidElement} = React;
  const baseId = useId();
  const getLanguageDisplayName = useCallback(language => {
    const displayNames = {
      [Languages.JAVASCRIPT]: "JavaScript",
      [Languages.PYTHON]: "Python",
      [Languages.RUBY]: "Ruby",
      [Languages.JAVA]: "Java",
      [Languages.DOTNET]: ".NET",
      [Languages.GO]: "Go",
      [Languages.SHELL]: "Shell",
      [Languages.MACOS]: "MacOS / Linux",
      [Languages.WINDOWS]: "Windows",
      [Languages.CMD]: "Command Prompt",
      [Languages.TYPESCRIPT]: "TypeScript",
      [Languages.HTML]: "HTML",
      [Languages.CSS]: "CSS",
      [Languages.JSON]: "JSON",
      [Languages.YAML]: "YAML",
      [Languages.XML]: "XML"
    };
    return displayNames[language] || language || "Code";
  }, []);
  const LANGUAGE_PREF_KEY = useMemo(() => 'mintlify-tabs-language-preference', []);
  const LANGUAGE_CHANGE_EVENT = useMemo(() => 'mintlify-tabs-language-change', []);
  const findMatchingLanguageTab = useCallback((tabs, targetLanguage) => {
    if (!targetLanguage?.trim() || !Array.isArray(tabs) || tabs.length === 0) return -1;
    const normalizedTarget = targetLanguage.toLowerCase().trim();
    return tabs.findIndex(tab => tab?.language?.toLowerCase().trim() === normalizedTarget);
  }, []);
  const getLanguagePreference = useCallback(() => {
    if (typeof window === 'undefined' || !window.localStorage) return null;
    try {
      const stored = localStorage.getItem(LANGUAGE_PREF_KEY);
      if (!stored) return null;
      const parsed = JSON.parse(stored);
      if (typeof parsed === 'object' && parsed.language && typeof parsed.language === 'string') {
        return parsed;
      }
      return null;
    } catch (error) {
      console.warn('Failed to parse language preference:', error);
      return null;
    }
  }, [LANGUAGE_PREF_KEY]);
  const setLanguagePreference = useCallback(language => {
    if (typeof window === 'undefined' || !window.localStorage || !language?.trim()) return;
    try {
      const preference = {
        language: language.trim(),
        timestamp: Date.now()
      };
      localStorage.setItem(LANGUAGE_PREF_KEY, JSON.stringify(preference));
      if (window.CustomEvent && window.dispatchEvent) {
        const event = new CustomEvent(LANGUAGE_CHANGE_EVENT, {
          detail: preference,
          bubbles: false,
          cancelable: false
        });
        window.dispatchEvent(event);
      }
    } catch (error) {
      console.warn('Failed to save language preference:', error);
    }
  }, [LANGUAGE_PREF_KEY, LANGUAGE_CHANGE_EVENT]);
  const generateTabId = useCallback((title, index) => {
    const cleanTitle = title?.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, '') || 'tab';
    return `${baseId}-${cleanTitle}-${index}`;
  }, [baseId]);
  const [announcement, setAnnouncement] = useState('');
  const announceToScreenReader = useCallback((message, duration = 1000) => {
    setAnnouncement(message);
    const timeoutId = setTimeout(() => setAnnouncement(''), duration);
    return () => clearTimeout(timeoutId);
  }, []);
  const processedTabs = useMemo(() => {
    if (!children) return [];
    const tabData = [];
    Children.forEach(children, (child, index) => {
      if (!isValidElement(child) || child.type !== CodeTab) {
        console.warn(`Invalid child at index ${index}. Expected CodeTab component.`);
        return;
      }
      const {title, language, disabled = false} = child.props || ({});
      const displayTitle = title || getLanguageDisplayName(language);
      if (!displayTitle || typeof displayTitle !== 'string') {
        console.warn(`CodeTab at index ${index} missing title and language props`);
        return;
      }
      tabData.push({
        title: displayTitle.trim(),
        language: language?.trim() || null,
        disabled: Boolean(disabled),
        content: child.props.children,
        id: generateTabId(displayTitle, index),
        index
      });
    });
    return tabData;
  }, [children, generateTabId]);
  const [activeIndex, setActiveIndex] = useState(0);
  useEffect(() => {
    if (processedTabs.length === 0) return;
    if (typeof defaultTab === 'number') {
      const clampedIndex = Math.max(0, Math.min(defaultTab, processedTabs.length - 1));
      setActiveIndex(clampedIndex);
      return;
    }
    if (typeof defaultTab === 'string' && defaultTab.trim()) {
      const matchIndex = processedTabs.findIndex(tab => tab.title?.toLowerCase() === defaultTab.toLowerCase().trim());
      if (matchIndex >= 0 && !processedTabs[matchIndex].disabled) {
        setActiveIndex(matchIndex);
        return;
      }
    }
    const firstEnabledIndex = processedTabs.findIndex(tab => !tab.disabled);
    setActiveIndex(firstEnabledIndex >= 0 ? firstEnabledIndex : 0);
  }, [processedTabs, defaultTab]);
  useEffect(() => {
    if (!syncLanguages || processedTabs.length === 0) return;
    const preference = getLanguagePreference();
    if (preference) {
      const matchIndex = findMatchingLanguageTab(processedTabs, preference.language);
      if (matchIndex >= 0) {
        setActiveIndex(matchIndex);
      }
    }
  }, [syncLanguages, processedTabs, getLanguagePreference, findMatchingLanguageTab]);
  const handleTabClick = useCallback(index => {
    const targetTab = processedTabs[index];
    if (!targetTab || targetTab.disabled || index === activeIndex) return;
    const previousIndex = activeIndex;
    setActiveIndex(index);
    const announcement = `${targetTab.title} tab selected. Tab ${index + 1} of ${processedTabs.length}.`;
    const cleanup = announceToScreenReader(announcement);
    if (syncLanguages && targetTab.language) {
      setLanguagePreference(targetTab.language);
    }
    onTabChange?.(index, targetTab, previousIndex);
    return cleanup;
  }, [processedTabs, activeIndex, syncLanguages, setLanguagePreference, onTabChange, announceToScreenReader]);
  useEffect(() => {
    if (!syncLanguages || typeof window === 'undefined') return;
    const handleLanguageChange = event => {
      try {
        const {language} = event.detail || ({});
        if (!language || typeof language !== 'string') return;
        const matchIndex = findMatchingLanguageTab(processedTabs, language);
        if (matchIndex >= 0 && matchIndex !== activeIndex && !processedTabs[matchIndex]?.disabled) {
          setActiveIndex(matchIndex);
          const currentTab = processedTabs[matchIndex];
          const announcement = `Synchronized to ${currentTab.title} tab. Tab ${matchIndex + 1} of ${processedTabs.length}.`;
          announceToScreenReader(announcement, 600);
          onTabChange?.(matchIndex, currentTab, activeIndex);
        }
      } catch (error) {
        console.warn('Error handling language change event:', error);
      }
    };
    window.addEventListener(LANGUAGE_CHANGE_EVENT, handleLanguageChange);
    return () => {
      window.removeEventListener(LANGUAGE_CHANGE_EVENT, handleLanguageChange);
    };
  }, [syncLanguages, processedTabs, activeIndex, findMatchingLanguageTab, LANGUAGE_CHANGE_EVENT, onTabChange, announceToScreenReader]);
  const handleKeyDown = useCallback((event, index) => {
    let targetIndex = -1;
    switch (event.key) {
      case 'ArrowLeft':
        event.preventDefault();
        targetIndex = index > 0 ? index - 1 : processedTabs.length - 1;
        break;
      case 'ArrowRight':
        event.preventDefault();
        targetIndex = index < processedTabs.length - 1 ? index + 1 : 0;
        break;
      case 'Enter':
      case ' ':
        event.preventDefault();
        handleTabClick(index);
        return;
      case 'Home':
        event.preventDefault();
        targetIndex = 0;
        break;
      case 'End':
        event.preventDefault();
        targetIndex = processedTabs.length - 1;
        break;
      default:
        return;
    }
    if (targetIndex !== -1) {
      setActiveIndex(targetIndex);
    }
  }, [processedTabs.length, handleTabClick]);
  if (processedTabs.length === 0) {
    return <div className="p-4 text-gray-500 italic text-center border border-gray-200 rounded-lg">
        No valid tabs found. Please check your CodeTab components.
      </div>;
  }
  const safeActiveIndex = Math.max(0, Math.min(activeIndex, processedTabs.length - 1));
  const activeTab = processedTabs[safeActiveIndex];
  return <div className={`tabs tab-container ${className}`} id={activeTab?.language || 'code-tabs'}>
      {}
      <div aria-live="polite" aria-atomic="true" className="sr-only">
        {announcement}
      </div>

      {}
      <ul role="tablist" aria-label={ariaLabel} className="not-prose mb-6 pb-[1px] flex-none min-w-full overflow-auto border-b border-gray-200 gap-x-6 flex dark:border-gray-200/10" data-component-part="tabs-list">
        {processedTabs.map((tab, index) => {
    const isActive = index === safeActiveIndex;
    const isDisabled = tab.disabled;
    return <li key={tab.id} id={tab.id} className="cursor-pointer">
              <button role="tab" aria-selected={isActive} aria-controls={`${tab.id}-panel`} aria-disabled={isDisabled} aria-setsize={processedTabs.length} aria-posinset={index + 1} tabIndex={isActive ? 0 : -1} disabled={isDisabled} onClick={() => handleTabClick(index)} onKeyDown={e => handleKeyDown(e, index)} className={isDisabled ? 'flex text-sm items-center gap-1.5 leading-6 font-semibold whitespace-nowrap pt-3 pb-2.5 -mb-px max-w-max border-b text-gray-400 border-transparent cursor-not-allowed opacity-50' : isActive ? 'flex text-sm items-center gap-1.5 leading-6 font-semibold whitespace-nowrap pt-3 pb-2.5 -mb-px max-w-max border-b text-primary dark:text-primary-light border-current' : 'flex text-sm items-center gap-1.5 leading-6 font-semibold whitespace-nowrap pt-3 pb-2.5 -mb-px max-w-max border-b text-gray-900 border-transparent hover:border-gray-300 dark:text-gray-200 dark:hover:border-gray-700'} data-component-part="tab-button" data-active={isActive}>
                {tab.title}
              </button>
            </li>;
  })}
      </ul>

      {}
      <div role="tabpanel" id={`${activeTab?.id}-panel`} aria-labelledby={activeTab?.id} aria-label={`${activeTab?.title} content, tab panel ${safeActiveIndex + 1} of ${processedTabs.length}`} tabIndex={0} className="prose dark:prose-dark overflow-x-auto" data-component-part="tab-content">
        {activeTab?.content}
      </div>
    </div>;
};

## Installation

<CodeTabs>
  <CodeTab title="Node.js" language={Languages.JAVASCRIPT}>
    Install the Oso Cloud Node.js client:

    ```bash theme={null}
    npm install oso-cloud@2.6.0
    ```

    **Requirements:**

    * Node.js 16 or later
    * TypeScript support included
  </CodeTab>

  <CodeTab language={Languages.PYTHON}>
    Install the Oso Cloud Python client:

    ```bash theme={null}
    pip install oso-cloud==2.6.0
    ```

    **Requirements:**

    * Python 3.8 or later
  </CodeTab>

  <CodeTab language={Languages.GO}>
    Install the Oso Cloud Go client:

    ```bash theme={null}
    go get github.com/osohq/go-oso-cloud/v2@latest
    ```

    **Requirements:**

    * Go 1.19 or later
  </CodeTab>

  <CodeTab language={Languages.JAVA}>
    Add the Oso Cloud Java client to your project:

    **Maven:**

    ```xml theme={null}
    <dependency>
        <groupId>com.osohq</groupId>
        <artifactId>oso-cloud</artifactId>
        <version>LATEST</version>
    </dependency>
    ```

    **Gradle:**

    ```groovy theme={null}
    implementation 'com.osohq:oso-cloud:LATEST'
    ```

    See [Maven Central page for com.osohq:oso-cloud](https://central.sonatype.com/artifact/com.osohq/oso-cloud) for the latest version.

    **Requirements:**

    * Java 11 or later
  </CodeTab>

  <CodeTab language={Languages.RUBY}>
    Install the Oso Cloud Ruby gem:

    ```bash theme={null}
    gem install oso-cloud -v 1.11.2
    ```

    Or add to Gemfile:

    ```ruby theme={null}
    gem 'oso-cloud', '~> 1.11.2'
    ```

    **Requirements:**

    * Ruby 3.0 or later
  </CodeTab>

  <CodeTab language={Languages.DOTNET}>
    Install the Oso Cloud .NET package:

    ```bash theme={null}
    dotnet add package OsoCloud --version 1.10.0
    ```

    **Requirements:**

    * .NET 6.0 or later
  </CodeTab>

  <CodeTab title="CLI" language={Languages.BASH}>
    **macOS/Linux**

    Install the Oso Cloud CLI:

    ```bash theme={null}
    curl -L https://cloud.osohq.com/install.sh | bash
    ```

    Verify installation:

    ```bash theme={null}
    which oso-cloud
    ```

    **Requirements:**

    * Unix-like system (Linux, macOS)
    * curl

    **Windows**

    Download and install the CLI executable:

    ```powershell theme={null}
    Invoke-WebRequest "https://d3i4cc4dqewpo9.cloudfront.net/latest/oso_cli.exe" -OutFile C:\<your_oso_cli_folder>\oso_cli.exe
    ```

    Replace `<your_oso_cli_folder>` with your preferred installation directory.

    Verify installation:

    ```powershell theme={null}
    C:\<your_oso_cli_folder>\oso_cli --help
    ```

    **Requirements:**

    * Windows PowerShell
    * Internet connection
  </CodeTab>
</CodeTabs>

## Environment Setup

First, [create or find an API key](https://ui.osohq.com/settings/?tab=api-keys) for your environment.

### macOS/Linux

Export the API key as `OSO_AUTH`:

```bash theme={null}
export OSO_AUTH=<your_oso_api_key>
```

### Windows

Store the API key as OSO\_AUTH for the current session:

```powershell theme={null}
Set-Item -Path env:OSO_AUTH -Value "<your_oso_api_key>"
```

## Client Initialization

<CodeTabs>
  <CodeTab title="Node.js" language={Languages.JAVASCRIPT}>
    ```javascript theme={null}
    import { Oso } from 'oso-cloud';

    const oso = new Oso(
      "https://cloud.osohq.com", 
      YOUR_API_KEY,
      {
        fallbackUrl: "http://localhost:8080",              // Optional: fallback server
        fetchTimeoutMillis: 1000,                          // Optional: request timeout
        dataBindings: "path/to/local_authorization_config.yaml"  // Optional: local auth config
      }
    );
    ```

    **TypeScript Support**

    Generate TypeScript types from your policy:

    ```bash theme={null}
    oso-cloud generate-types typescript path/to/policy.polar > path/to/polarTypes.d.ts
    ```

    Then use with your client:

    ```typescript theme={null}
    import type { PolarTypes } from "./polarTypes";

    const oso = new Oso<PolarTypes>("https://cloud.osohq.com", YOUR_API_KEY);
    ```

    **Signature:** `new Oso(url, apiKey, options?)`
  </CodeTab>

  <CodeTab language={Languages.PYTHON}>
    ```python theme={null}
    from oso_cloud import Oso

    oso = Oso(
        url="https://cloud.osohq.com", 
        api_key=YOUR_API_KEY,
        fallback_url="http://localhost:8080",              # Optional: fallback server
        data_bindings="path/to/local_authorization_config.yaml"  # Optional: local auth config
    )
    ```

    **Signature:** `Oso(url, api_key, fallback_url=None, data_bindings=None)`
  </CodeTab>

  <CodeTab language={Languages.GO}>
    ```go theme={null}
    import oso "github.com/osohq/go-oso-cloud/v2"

    // Basic client
    osoClient := oso.NewClient("https://cloud.osohq.com", YOUR_API_KEY)

    // With fallback URL
    osoClient := oso.NewClientWithFallbackUrl(
        "https://cloud.osohq.com", 
        YOUR_API_KEY, 
        "http://localhost:8080"  // Optional: fallback server
    )

    // With data bindings
    osoClient := oso.NewClientWithDataBindings(
        "https://cloud.osohq.com", 
        YOUR_API_KEY, 
        "path/to/local_authorization_config.yaml"  // Optional: local auth config
    )
    ```

    **Signature:** `oso.NewClient(url, apiKey)`
  </CodeTab>

  <CodeTab language={Languages.JAVA}>
    ```java theme={null}
    import com.osohq.oso.Oso;

    Oso oso = new Oso(
        YOUR_API_KEY,
        null,                                              // Optional: custom URL (null = default)
        URI.create("http://localhost:8080"),               // Optional: fallback server
        "path/to/local_authorization_config.yaml"         // Optional: local auth config
    );
    ```

    **Signature:** `new Oso(apiKey, url?, fallbackUrl?, dataBindings?)`
  </CodeTab>

  <CodeTab language={Languages.RUBY}>
    ```ruby theme={null}
    require 'oso-cloud'

    oso = OsoCloud::Oso.new(
      url: "https://cloud.osohq.com", 
      api_key: YOUR_API_KEY,
      fallback_url: "http://localhost:8080",              # Optional: fallback server
      data_bindings: "path/to/local_authorization_config.yaml"  # Optional: local auth config
    )
    ```

    **Signature:** `OsoCloud::Oso.new(url:, api_key:, fallback_url:, data_bindings:)`
  </CodeTab>

  <CodeTab language={Languages.DOTNET}>
    ```csharp theme={null}
    using OsoCloud;

    var oso = new Oso(
        "https://api.osohq.com", 
        YOUR_API_KEY,
        "http://localhost:8080",                           // Optional: fallback server
        dataBindings: "path/to/local_authorization_config.yaml"  // Optional: local auth config
    );
    ```

    **Signature:** `new Oso(url, apiKey, fallbackUrl?, dataBindings?)`
  </CodeTab>

  <CodeTab title="CLI" language={Languages.BASH}>
    **Basic Usage**

    ```bash theme={null}
    # macOS/Linux
    oso-cloud <command> [options]

    # Windows  
    oso_cli <command> [options]
    ```

    **Global Options**

    The CLI supports the following global options:

    * **`-v`/`--verbose`**: Increases verbosity of log output
    * **`-q`/`--quiet`**: Suppresses informational log output
    * **`--json`**: Outputs log messages as JSON objects
    * **`--debug-http`**: Outputs detailed HTTP request information
    * **`--disable-self-update-check`**: Skips automatic version check
    * **`--dns-servers`**: Sets custom DNS nameservers
    * **`--ca-path`**: Adds custom CA bundle to trust store

    **Configuration**

    The CLI uses the `OSO_AUTH` environment variable for authentication. Make sure you've set it as described in the Environment Setup section above.
  </CodeTab>
</CodeTabs>
