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

# Azure Blob Storage OAuth 2.0 (Entra ID) connector profile – StackOne setup guide

> Set up the OAuth 2.0 (Entra ID) connector profile for Azure Blob Storage in StackOne. One-time admin setup required before your users can link Azure Blob Storage accounts via Hub.

<Warning>You must have at least Application Developer permissions in Microsoft Entra ID to register applications. An administrator must grant consent for the required Azure Storage API permissions.</Warning>

<Panel>
  <div className="not-prose guides-scope-selector" data-guides-scope-selector data-guide-actions-json="[{&#x22;id&#x22;:&#x22;azureblobstorage_list_containers&#x22;,&#x22;label&#x22;:&#x22;List Containers&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]},{&#x22;id&#x22;:&#x22;azureblobstorage_get_blob_service_properties&#x22;,&#x22;label&#x22;:&#x22;Get Blob Service Properties&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]},{&#x22;id&#x22;:&#x22;azureblobstorage_set_blob_service_properties&#x22;,&#x22;label&#x22;:&#x22;Set Blob Service Properties&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]},{&#x22;id&#x22;:&#x22;azureblobstorage_create_container&#x22;,&#x22;label&#x22;:&#x22;Create Container&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]},{&#x22;id&#x22;:&#x22;azureblobstorage_get_container_properties&#x22;,&#x22;label&#x22;:&#x22;Get Container Properties&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]},{&#x22;id&#x22;:&#x22;azureblobstorage_get_container_metadata&#x22;,&#x22;label&#x22;:&#x22;Get Container Metadata&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]},{&#x22;id&#x22;:&#x22;azureblobstorage_set_container_metadata&#x22;,&#x22;label&#x22;:&#x22;Set Container Metadata&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]},{&#x22;id&#x22;:&#x22;azureblobstorage_delete_container&#x22;,&#x22;label&#x22;:&#x22;Delete Container&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]},{&#x22;id&#x22;:&#x22;azureblobstorage_get_container_acl&#x22;,&#x22;label&#x22;:&#x22;Get Container ACL&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]},{&#x22;id&#x22;:&#x22;azureblobstorage_set_container_acl&#x22;,&#x22;label&#x22;:&#x22;Set Container ACL&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]},{&#x22;id&#x22;:&#x22;azureblobstorage_list_blobs&#x22;,&#x22;label&#x22;:&#x22;List Blobs&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]},{&#x22;id&#x22;:&#x22;azureblobstorage_upload_blob&#x22;,&#x22;label&#x22;:&#x22;Upload Blob&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]},{&#x22;id&#x22;:&#x22;azureblobstorage_download_blob&#x22;,&#x22;label&#x22;:&#x22;Download Blob&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]},{&#x22;id&#x22;:&#x22;azureblobstorage_get_blob_properties&#x22;,&#x22;label&#x22;:&#x22;Get Blob Properties&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]},{&#x22;id&#x22;:&#x22;azureblobstorage_delete_blob&#x22;,&#x22;label&#x22;:&#x22;Delete Blob&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]},{&#x22;id&#x22;:&#x22;azureblobstorage_copy_blob&#x22;,&#x22;label&#x22;:&#x22;Copy Blob&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]},{&#x22;id&#x22;:&#x22;azureblobstorage_set_blob_tier&#x22;,&#x22;label&#x22;:&#x22;Set Blob Tier&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]},{&#x22;id&#x22;:&#x22;azureblobstorage_create_blob_snapshot&#x22;,&#x22;label&#x22;:&#x22;Create Blob Snapshot&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]},{&#x22;id&#x22;:&#x22;azureblobstorage_undelete_blob&#x22;,&#x22;label&#x22;:&#x22;Undelete Blob&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]},{&#x22;id&#x22;:&#x22;azureblobstorage_set_blob_properties&#x22;,&#x22;label&#x22;:&#x22;Set Blob Properties&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]},{&#x22;id&#x22;:&#x22;azureblobstorage_abort_copy_blob&#x22;,&#x22;label&#x22;:&#x22;Abort Copy Blob&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]},{&#x22;id&#x22;:&#x22;azureblobstorage_get_blob_metadata&#x22;,&#x22;label&#x22;:&#x22;Get Blob Metadata&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]},{&#x22;id&#x22;:&#x22;azureblobstorage_set_blob_metadata&#x22;,&#x22;label&#x22;:&#x22;Set Blob Metadata&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]},{&#x22;id&#x22;:&#x22;azureblobstorage_get_blob_tags&#x22;,&#x22;label&#x22;:&#x22;Get Blob Tags&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]},{&#x22;id&#x22;:&#x22;azureblobstorage_set_blob_tags&#x22;,&#x22;label&#x22;:&#x22;Set Blob Tags&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]},{&#x22;id&#x22;:&#x22;azureblobstorage_find_blobs_by_tags&#x22;,&#x22;label&#x22;:&#x22;Find Blobs By Tags&#x22;,&#x22;scopes&#x22;:[&#x22;https://storage.azure.com/user_impersonation&#x22;]}]" style={{ borderRadius: '8px', padding: '16px', marginBottom: '24px' }}>
    <div className="guides-scope-selector__title" style={{ fontSize: '16px', fontWeight: '600', marginBottom: '12px' }}>Select Actions to adjust the guide</div>
    <div className="guides-scope-selector__muted" style={{ fontSize: '13px', marginBottom: '12px' }}>Some actions may require additional configuration in the provider to be accessible. Choose the actions you need and the guide will be updated.</div>

    <div style={{ display: 'flex', gap: '8px', marginBottom: '12px', flexWrap: 'wrap' }}>
      <input type="text" placeholder="Search actions..." className="guides-scope-selector__input" data-guide-action-search style={{ padding: '8px 12px', borderRadius: '6px', fontSize: '13px', flex: 1, minWidth: '160px' }} />

      <button type="button" className="guides-scope-selector__quick-btn" data-guide-select-all style={{ padding: '6px 10px', borderRadius: '6px', fontSize: '12px', cursor: 'pointer' }}>Select all</button>
      <button type="button" className="guides-scope-selector__quick-btn" data-guide-clear style={{ padding: '6px 10px', borderRadius: '6px', fontSize: '12px', cursor: 'pointer' }}>Clear</button>
    </div>

    <div className="guides-scope-selector__list" style={{ maxHeight: '240px', overflowY: 'auto', borderRadius: '6px', marginBottom: '12px' }}>
      <div className="guides-scope-selector__list-header" style={{ display: 'flex', alignItems: 'center', gap: '10px', padding: '8px 12px', fontSize: '12px', fontWeight: '600', position: 'sticky', top: 0, zIndex: 1 }}>
        <div style={{ width: '16px', flexShrink: 0 }} />

        <div style={{ flex: 1, textAlign: 'left' }}>Action</div>
        <div style={{ minWidth: '120px', marginLeft: 'auto', textAlign: 'right' }}>Scope(s)</div>
      </div>

      <div className="guides-scope-selector__muted" data-guide-loading style={{ padding: '16px', textAlign: 'center', fontSize: '13px' }}>Loading actions...</div>
      <div className="guides-scope-selector__muted" data-guide-no-results hidden style={{ padding: '16px', textAlign: 'center', fontSize: '13px' }}>No actions match your search.</div>
    </div>

    <div className="guides-scope-selector__url-section" style={{ marginTop: '12px', paddingTop: '12px' }}>
      <div className="guides-scope-selector__muted" style={{ fontSize: '12px', fontWeight: '500', marginBottom: '6px' }}>Dynamic Guide URL</div>

      <div style={{ display: 'flex', alignItems: 'center', gap: '8px', flexWrap: 'wrap' }}>
        <input type="text" readOnly className="guides-scope-selector__input" data-guide-url style={{ flex: 1, minWidth: '200px', padding: '8px 10px', borderRadius: '6px', fontSize: '12px', fontFamily: 'monospace' }} />

        <button type="button" className="guides-scope-selector__copy-btn" data-guide-copy-url style={{ width: '120px', padding: '8px 14px', borderRadius: '6px', fontSize: '13px', fontWeight: '500', cursor: 'pointer', whiteSpace: 'nowrap', marginLeft: 'auto' }}>Copy URL</button>
      </div>

      <div style={{ marginTop: '12px' }}>
        <div className="guides-scope-selector__muted" style={{ fontSize: '12px', fontWeight: '500', marginBottom: '6px' }}>Scopes Selected</div>

        <div style={{ display: 'flex', alignItems: 'stretch', gap: '8px', flexWrap: 'wrap' }}>
          <pre className="guides-scope-selector__input" role="textbox" aria-readonly="true" tabIndex={0} data-guide-scopes-output style={{ flex: 1, minWidth: '200px', minHeight: '88px', maxHeight: '120px', overflowY: 'auto', margin: 0, padding: '8px 10px', borderRadius: '6px', fontSize: '12px', fontFamily: 'monospace', whiteSpace: 'pre-wrap' }} />

          <div className="guides-scope-selector__muted" style={{ display: 'flex', flexDirection: 'column', gap: '8px', fontSize: '12px', fontWeight: '500', flexShrink: 0, alignItems: 'flex-start' }}>
            <div style={{ whiteSpace: 'nowrap' }}>Separator</div>

            <select className="guides-scope-selector__input" data-guide-scope-delimiter style={{ width: '100%', padding: '6px 10px', borderRadius: '6px', fontSize: '12px' }}>
              <option value="space">Space</option>
              <option value="comma">Comma</option>
              <option value="semicolon">Semicolon</option>
              <option value="pipe">Pipe</option>
              <option value="newline">Newline</option>
            </select>

            <button type="button" className="guides-scope-selector__copy-btn" data-guide-copy-scopes style={{ width: '120px', padding: '8px 14px', borderRadius: '6px', fontSize: '13px', fontWeight: '500', cursor: 'pointer', whiteSpace: 'nowrap' }}>Copy scopes</button>
          </div>
        </div>
      </div>
    </div>
  </div>
</Panel>

<section data-guide-section data-guide-scopes="">
  <h2>Register your application in Microsoft Entra ID</h2>

  <p>Register an application in Microsoft Entra ID to obtain OAuth 2.0 credentials for StackOne.</p>

  <Steps>
    <Step title="Sign in to Microsoft Entra admin center">
      <div data-guide-step data-guide-scopes="" data-guide-display-scopes-list="">
        <p>Sign in to your <a href="https://entra.microsoft.com" target="_blank" rel="noopener noreferrer">Microsoft Entra admin center</a> as at least an Application Developer.</p>

        <ul>
          <li>If you have access to multiple tenants, click the <strong>Settings</strong> (gear) icon in the top-right corner, then select the desired tenant from the list under <strong>Directory + subscription</strong>.</li>
          <li>Navigate to <strong>Identity</strong> > <strong>Applications</strong> > <strong>App registrations</strong>.</li>
        </ul>
      </div>
    </Step>

    <Step title="Create a new app registration">
      <div data-guide-step data-guide-scopes="" data-guide-display-scopes-list="">
        <p>Click <strong>New registration</strong> and complete the form.</p>

        <ul>
          <li>Name: `StackOne Azure Blob Storage Integration`</li>
          <li>Select <strong>Accounts in this organizational directory only</strong> (single tenant).</li>
          <li>Click <strong>Register</strong>.</li>
        </ul>
      </div>
    </Step>

    <Step title="Copy the application (client) ID">
      <div data-guide-step data-guide-scopes="" data-guide-display-scopes-list="">
        <p>From the app's <strong>Overview</strong> page, copy the <strong>Application (client) ID</strong> and <strong>Directory (tenant) ID</strong> and store them securely for use later.</p>
      </div>
    </Step>
  </Steps>
</section>

<section data-guide-section data-guide-scopes="">
  <h2>Configure the redirect URI</h2>

  <p>Register the OAuth 2.0 callback URL so Microsoft Entra can return the authorization code to StackOne.</p>

  <Steps>
    <Step title="Add the redirect URI">
      <div data-guide-step data-guide-scopes="" data-guide-display-scopes-list="">
        <p>Navigate to <strong>Authentication</strong> under <strong>Manage</strong>.</p>

        <ul>
          <li>Click <strong>Add a platform</strong> and select <strong>Web</strong>.</li>
          <li>Enter the redirect URI: `https://api.stackone.com/connect/oauth2/azureblobstorage/callback`</li>
          <li>Click <strong>Configure</strong>.</li>
        </ul>
      </div>
    </Step>
  </Steps>
</section>

<section data-guide-section data-guide-scopes="">
  <h2>Configure API permissions</h2>

  <p>Grant the Azure Storage delegated permission and admin consent for your application.</p>

  <Steps>
    <Step title="Add Azure Storage permissions">
      <div data-guide-step data-guide-scopes="https://storage.azure.com/user_impersonation,offline_access" data-guide-display-scopes-list="https://storage.azure.com/user_impersonation,offline_access">
        <div className="connector-guide-actions-badge" data-guide-actions-badge data-guide-actions-badge-scopes="https://storage.azure.com/user_impersonation,offline_access" style={{ display: 'block', width: 'fit-content', maxWidth: '100%', padding: '2px 8px', borderRadius: '8px', fontSize: '12px', marginBottom: '8px', marginTop: '-10px', whiteSpace: 'nowrap', overflowX: 'auto', overflowY: 'hidden', msOverflowStyle: 'none', scrollbarWidth: 'none' }}>
          <span>Enables actions: </span><span data-guide-actions-badge-labels>Abort Copy Blob, Copy Blob, Create Blob Snapshot, Create Container, Delete Blob, Delete Container, Download Blob, Find Blobs By Tags, Get Blob Metadata, Get Blob Properties, Get Blob Service Properties, Get Blob Tags, Get Container ACL, Get Container Metadata, Get Container Properties, List Blobs, List Containers, Set Blob Metadata, Set Blob Properties, Set Blob Service Properties, Set Blob Tags, Set Blob Tier, Set Container ACL, Set Container Metadata, Undelete Blob, Upload Blob</span>
        </div>

        <p>Navigate to <strong>API permissions</strong> under <strong>Manage</strong>.</p>

        <ul>
          <li>Click <strong>Add a permission</strong>.</li>
          <li>Select <strong>Azure Storage</strong> from the list.</li>
          <li>Choose <strong>Delegated permissions</strong>.</li>
          <li>Select <strong>user\_impersonation</strong> to allow access as the signed-in user.</li>
          <li>Click <strong>Add permissions</strong>.</li>
        </ul>

        <div style={{ marginTop: '8px' }} data-guide-display-scopes>
          <div className="connector-guide-scopes-container">
            <ul className="not-prose" style={{ listStyleType: "'- '", paddingLeft: '1em', margin: 0 }}>
              <li style={{ overflowWrap: 'anywhere', wordBreak: 'break-word' }} data-guide-display-scope="https://storage.azure.com/user_impersonation">
                <button type="button" className="connector-guide-scope-copy" aria-label="Copy https://storage.azure.com/user_impersonation" title="Copy scope" data-copy="https://storage.azure.com/user_impersonation">
                  <span className="connector-guide-scope-copy__label">[https://storage.azure.com/user\_impersonation](https://storage.azure.com/user_impersonation)</span>
                  <span className="connector-guide-scope-copy__icon" aria-hidden="true">⧉</span>
                </button>
              </li>

              <li style={{ overflowWrap: 'anywhere', wordBreak: 'break-word' }} data-guide-display-scope="offline_access">
                <button type="button" className="connector-guide-scope-copy" aria-label="Copy offline_access" title="Copy scope" data-copy="offline_access">
                  <span className="connector-guide-scope-copy__label">offline\_access</span>
                  <span className="connector-guide-scope-copy__icon" aria-hidden="true">⧉</span>
                </button>
              </li>
            </ul>
          </div>
        </div>
      </div>
    </Step>

    <Step title="Grant admin consent">
      <div data-guide-step data-guide-scopes="" data-guide-display-scopes-list="">
        <p>Click <strong>Grant admin consent for \[tenant name]</strong> and confirm to enable the permission for all users.</p>
      </div>
    </Step>
  </Steps>
</section>

<section data-guide-section data-guide-scopes="">
  <h2>Assign Azure RBAC roles on the storage account</h2>

  <p>Entra ID authenticates the user, but Azure Storage authorizes operations via Azure RBAC roles assigned on the storage account. Assign the role that matches the operations StackOne will perform.</p>

  <Steps>
    <Step title="Assign Storage Blob Data Contributor">
      <div data-guide-step data-guide-scopes="" data-guide-display-scopes-list="">
        <p>Grants read, write, and delete on blobs and containers — required for most StackOne actions.</p>

        <ul>
          <li>Open the storage account in the <a href="https://portal.azure.com" target="_blank" rel="noopener noreferrer">Azure portal</a>.</li>
          <li>Select <strong>Access Control (IAM)</strong> in the left sidebar.</li>
          <li>Click <strong>Add</strong> > <strong>Add role assignment</strong>.</li>
          <li>Search for and select <strong>Storage Blob Data Contributor</strong>, then click <strong>Next</strong>.</li>
          <li>Under <strong>Members</strong>, select <strong>User, group, or service principal</strong> and click <strong>Select members</strong>.</li>
          <li>Search for the OAuth user who will connect StackOne and click <strong>Select</strong>.</li>
          <li>Click <strong>Review + assign</strong>.</li>
        </ul>
      </div>
    </Step>

    <Step title="Assign Storage Blob Data Owner (optional)">
      <div data-guide-step data-guide-scopes="" data-guide-display-scopes-list="">
        <p>Required only if StackOne will use blob tag actions (<strong>Get Blob Tags</strong>, <strong>Set Blob Tags</strong>, <strong>Find Blobs By Tags</strong>). This role is a superset of Storage Blob Data Contributor.</p>

        <ul>
          <li>Repeat the steps above and select <strong>Storage Blob Data Owner</strong> instead.</li>
        </ul>
      </div>
    </Step>
  </Steps>
</section>

<section data-guide-section data-guide-scopes="">
  <h2>Create a client secret</h2>

  <p>Generate a secret that StackOne will use to authenticate the app registration against Microsoft Entra.</p>

  <Steps>
    <Step title="Generate the secret">
      <div data-guide-step data-guide-scopes="" data-guide-display-scopes-list="">
        <p>Navigate to <strong>Certificates & secrets</strong> under <strong>Manage</strong>.</p>

        <ul>
          <li>Click <strong>New client secret</strong>.</li>
          <li>Description: `StackOne Integration`</li>
          <li>Select an expiration period.</li>
          <li>Click <strong>Add</strong>.</li>
          <li>Copy the secret <strong>Value</strong> immediately and store it securely for use later — it is only displayed once.</li>
        </ul>
      </div>
    </Step>
  </Steps>
</section>

## Creating the StackOne Connector Profile

To create the Connector Profile in StackOne for <strong>Azure Blob Storage</strong>:

<Steps>
  <Step title="Navigate to Connector Profiles">
    Login to StackOne and navigate to [Connector Profiles](https://app.stackone.com/connector_profiles)
  </Step>

  <Step title="Create New Connector Profile">
    <ul>
      <li>Click <strong>+ Connector Profile</strong></li>
      <li>Search for and select <strong>Azure Blob Storage</strong></li>
      <li>Select <strong>Type</strong> as <strong>OAuth 2.0 (Entra ID)</strong></li>

      <li>
        Fill out the fields using details retrieved from your provider:

        <ul style={{ marginLeft: '20px' }}>
          <li><strong>Tenant ID</strong></li>
          <li><strong>Client ID</strong></li>
          <li><strong>Client Secret</strong></li>
          <li><strong>Scopes</strong> (Optional)</li>
        </ul>
      </li>

      <li>(Optional) Select <strong>Actions</strong> to be enabled for this Connector Profile</li>
      <li>Click <strong>Create profile</strong></li>
    </ul>
  </Step>
</Steps>

Congratulations! The new Connector Profile will now show up in your project ready to be used. You can now continue to <a href="/guides/accounts-section#linking-accounts">Link Accounts</a> for <strong>Azure Blob Storage</strong>.
