> ## 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.

# Airtable OAuth 2.0 connector profile – StackOne setup guide

> Set up the OAuth 2.0 connector profile for Airtable in StackOne. One-time admin setup required before your users can link Airtable accounts via Hub.

<Warning>You need an Airtable account to register an OAuth integration in the Developer Hub.</Warning>

<Panel>
  <div className="not-prose guides-scope-selector" data-guides-scope-selector data-guide-actions-json="[{&#x22;id&#x22;:&#x22;airtable_get_current_user&#x22;,&#x22;label&#x22;:&#x22;Get Current User&#x22;,&#x22;scopes&#x22;:[&#x22;user.email:read&#x22;]},{&#x22;id&#x22;:&#x22;airtable_list_bases&#x22;,&#x22;label&#x22;:&#x22;List Bases&#x22;,&#x22;scopes&#x22;:[&#x22;schema.bases:read&#x22;]},{&#x22;id&#x22;:&#x22;airtable_create_base&#x22;,&#x22;label&#x22;:&#x22;Create Base&#x22;,&#x22;scopes&#x22;:[&#x22;schema.bases:write&#x22;]},{&#x22;id&#x22;:&#x22;airtable_get_base_schema&#x22;,&#x22;label&#x22;:&#x22;Get Base Schema&#x22;,&#x22;scopes&#x22;:[&#x22;schema.bases:read&#x22;]},{&#x22;id&#x22;:&#x22;airtable_create_table&#x22;,&#x22;label&#x22;:&#x22;Create Table&#x22;,&#x22;scopes&#x22;:[&#x22;schema.bases:write&#x22;]},{&#x22;id&#x22;:&#x22;airtable_update_table&#x22;,&#x22;label&#x22;:&#x22;Update Table&#x22;,&#x22;scopes&#x22;:[&#x22;schema.bases:write&#x22;]},{&#x22;id&#x22;:&#x22;airtable_create_field&#x22;,&#x22;label&#x22;:&#x22;Create Field&#x22;,&#x22;scopes&#x22;:[&#x22;schema.bases:write&#x22;]},{&#x22;id&#x22;:&#x22;airtable_update_field&#x22;,&#x22;label&#x22;:&#x22;Update Field&#x22;,&#x22;scopes&#x22;:[&#x22;schema.bases:write&#x22;]},{&#x22;id&#x22;:&#x22;airtable_list_records&#x22;,&#x22;label&#x22;:&#x22;List Records&#x22;,&#x22;scopes&#x22;:[&#x22;data.records:read&#x22;]},{&#x22;id&#x22;:&#x22;airtable_get_record&#x22;,&#x22;label&#x22;:&#x22;Get Record&#x22;,&#x22;scopes&#x22;:[&#x22;data.records:read&#x22;]},{&#x22;id&#x22;:&#x22;airtable_create_records&#x22;,&#x22;label&#x22;:&#x22;Create Records&#x22;,&#x22;scopes&#x22;:[&#x22;data.records:write&#x22;]},{&#x22;id&#x22;:&#x22;airtable_update_record&#x22;,&#x22;label&#x22;:&#x22;Update Record&#x22;,&#x22;scopes&#x22;:[&#x22;data.records:write&#x22;]},{&#x22;id&#x22;:&#x22;airtable_replace_record&#x22;,&#x22;label&#x22;:&#x22;Replace Record&#x22;,&#x22;scopes&#x22;:[&#x22;data.records:write&#x22;]},{&#x22;id&#x22;:&#x22;airtable_update_records&#x22;,&#x22;label&#x22;:&#x22;Update Multiple Records&#x22;,&#x22;scopes&#x22;:[&#x22;data.records:write&#x22;]},{&#x22;id&#x22;:&#x22;airtable_delete_record&#x22;,&#x22;label&#x22;:&#x22;Delete Record&#x22;,&#x22;scopes&#x22;:[&#x22;data.records:write&#x22;]},{&#x22;id&#x22;:&#x22;airtable_list_comments&#x22;,&#x22;label&#x22;:&#x22;List Comments&#x22;,&#x22;scopes&#x22;:[&#x22;data.recordComments:read&#x22;]},{&#x22;id&#x22;:&#x22;airtable_create_comment&#x22;,&#x22;label&#x22;:&#x22;Create Comment&#x22;,&#x22;scopes&#x22;:[&#x22;data.recordComments:write&#x22;]},{&#x22;id&#x22;:&#x22;airtable_update_comment&#x22;,&#x22;label&#x22;:&#x22;Update Comment&#x22;,&#x22;scopes&#x22;:[&#x22;data.recordComments:write&#x22;]},{&#x22;id&#x22;:&#x22;airtable_delete_comment&#x22;,&#x22;label&#x22;:&#x22;Delete Comment&#x22;,&#x22;scopes&#x22;:[&#x22;data.recordComments:write&#x22;]},{&#x22;id&#x22;:&#x22;airtable_list_webhooks&#x22;,&#x22;label&#x22;:&#x22;List Webhooks&#x22;,&#x22;scopes&#x22;:[&#x22;webhook:manage&#x22;]},{&#x22;id&#x22;:&#x22;airtable_create_webhook&#x22;,&#x22;label&#x22;:&#x22;Create Webhook&#x22;,&#x22;scopes&#x22;:[&#x22;webhook:manage&#x22;]},{&#x22;id&#x22;:&#x22;airtable_refresh_webhook&#x22;,&#x22;label&#x22;:&#x22;Refresh Webhook&#x22;,&#x22;scopes&#x22;:[&#x22;webhook:manage&#x22;]},{&#x22;id&#x22;:&#x22;airtable_delete_webhook&#x22;,&#x22;label&#x22;:&#x22;Delete Webhook&#x22;,&#x22;scopes&#x22;:[&#x22;webhook:manage&#x22;]},{&#x22;id&#x22;:&#x22;airtable_list_webhook_payloads&#x22;,&#x22;label&#x22;:&#x22;List Webhook Payloads&#x22;,&#x22;scopes&#x22;:[&#x22;webhook:manage&#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 an OAuth Integration</h2>

  <p>Create a new OAuth integration in the Airtable Developer Hub to obtain your Client ID and Client Secret.</p>

  <Steps>
    <Step title="Access the Developer Hub">
      <div data-guide-step data-guide-scopes="" data-guide-display-scopes-list="">
        <p>Navigate to the Airtable Developer Hub where OAuth integrations are managed.</p>

        <ul>
          <li>Sign in to your <a href="https://airtable.com/" target="_blank" rel="noopener noreferrer">Airtable account</a></li>
          <li>Click your account profile icon in the top-right corner</li>
          <li>Select <strong>Developer hub</strong> from the dropdown menu</li>
        </ul>
      </div>
    </Step>

    <Step title="Navigate to OAuth integrations">
      <div data-guide-step data-guide-scopes="" data-guide-display-scopes-list="">
        <p>Open the OAuth integrations page to register a new app.</p>

        <ul>
          <li>In the left sidebar, click <strong>OAuth integrations</strong></li>
          <li>Click the <strong>Register an OAuth integration</strong> button</li>
        </ul>
      </div>
    </Step>

    <Step title="Enter integration details">
      <div data-guide-step data-guide-scopes="" data-guide-display-scopes-list="">
        <p>Fill in the required information for your OAuth integration.</p>

        <ul>
          <li>Enter a <strong>Name</strong> for the integration (e.g., StackOne Integration)</li>
          <li>Enter the <strong>OAuth redirect URL</strong>: `https://api.stackone.com/connect/oauth2/airtable/callback`</li>
          <li>Click <strong>Register integration</strong> to create the app</li>
        </ul>
      </div>
    </Step>
  </Steps>
</section>

<section data-guide-section data-guide-scopes="">
  <h2>Configure Scopes and Permissions</h2>

  <p>Set up the required scopes for your OAuth integration to access Airtable data.</p>

  <Steps>
    <Step title="Add required scopes">
      <div data-guide-step data-guide-scopes="user.email:read,schema.bases:read,schema.bases:write,data.records:read,data.records:write,data.recordComments:read,data.recordComments:write,webhook:manage" data-guide-display-scopes-list="user.email:read,schema.bases:read,schema.bases:write,data.records:read,data.records:write,data.recordComments:read,data.recordComments:write,webhook:manage">
        <div className="connector-guide-actions-badge" data-guide-actions-badge data-guide-actions-badge-scopes="user.email:read,schema.bases:read,schema.bases:write,data.records:read,data.records:write,data.recordComments:read,data.recordComments:write,webhook:manage" 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>Create Base, Create Comment, Create Field, Create Records, Create Table, Create Webhook, Delete Comment, Delete Record, Delete Webhook, Get Base Schema, Get Current User, Get Record, List Bases, List Comments, List Records, List Webhook Payloads, List Webhooks, Refresh Webhook, Replace Record, Update Comment, Update Field, Update Multiple Records, Update Record, Update Table</span>
        </div>

        <p>Scroll to the <strong>Scopes</strong> section on the integration settings page and select each required scope by clicking the checkbox next to it. Choose the minimum scopes needed for your use case.</p>

        <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="user.email:read">
                <button type="button" className="connector-guide-scope-copy" aria-label="Copy user.email:read" title="Copy scope" data-copy="user.email:read">
                  <span className="connector-guide-scope-copy__label">user.email:read</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="schema.bases:read">
                <button type="button" className="connector-guide-scope-copy" aria-label="Copy schema.bases:read" title="Copy scope" data-copy="schema.bases:read">
                  <span className="connector-guide-scope-copy__label">schema.bases:read</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="schema.bases:write">
                <button type="button" className="connector-guide-scope-copy" aria-label="Copy schema.bases:write" title="Copy scope" data-copy="schema.bases:write">
                  <span className="connector-guide-scope-copy__label">schema.bases:write</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="data.records:read">
                <button type="button" className="connector-guide-scope-copy" aria-label="Copy data.records:read" title="Copy scope" data-copy="data.records:read">
                  <span className="connector-guide-scope-copy__label">data.records:read</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="data.records:write">
                <button type="button" className="connector-guide-scope-copy" aria-label="Copy data.records:write" title="Copy scope" data-copy="data.records:write">
                  <span className="connector-guide-scope-copy__label">data.records:write</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="data.recordComments:read">
                <button type="button" className="connector-guide-scope-copy" aria-label="Copy data.recordComments:read" title="Copy scope" data-copy="data.recordComments:read">
                  <span className="connector-guide-scope-copy__label">data.recordComments:read</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="data.recordComments:write">
                <button type="button" className="connector-guide-scope-copy" aria-label="Copy data.recordComments:write" title="Copy scope" data-copy="data.recordComments:write">
                  <span className="connector-guide-scope-copy__label">data.recordComments:write</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="webhook:manage">
                <button type="button" className="connector-guide-scope-copy" aria-label="Copy webhook:manage" title="Copy scope" data-copy="webhook:manage">
                  <span className="connector-guide-scope-copy__label">webhook:manage</span>
                  <span className="connector-guide-scope-copy__icon" aria-hidden="true">⧉</span>
                </button>
              </li>
            </ul>
          </div>
        </div>
      </div>
    </Step>

    <Step title="Save your changes">
      <div data-guide-step data-guide-scopes="" data-guide-display-scopes-list="">
        <p>Apply the scope configuration.</p>

        <ul>
          <li>Click <strong>Save changes</strong> to apply the selected scopes.</li>
          <li>A confirmation message will appear when changes are saved.</li>
        </ul>
      </div>
    </Step>
  </Steps>
</section>

<section data-guide-section data-guide-scopes="">
  <h2>Retrieve Client Credentials</h2>

  <p>Copy your Client ID and Client Secret for use with StackOne.</p>

  <Steps>
    <Step title="Copy the Client ID">
      <div data-guide-step data-guide-scopes="" data-guide-display-scopes-list="">
        <p>Find and copy your integration's Client ID.</p>

        <ul>
          <li>On the integration settings page, locate the <strong>Client ID</strong> field</li>
          <li>Copy the Client ID value</li>
        </ul>
      </div>
    </Step>

    <Step title="Generate and copy the Client Secret">
      <div data-guide-step data-guide-scopes="" data-guide-display-scopes-list="">
        <p>Generate a Client Secret for your integration.</p>

        <ul>
          <li>Click <strong>Generate a client secret</strong></li>
          <li><strong>Important:</strong> Copy the Client Secret immediately and store it securely. The secret is only displayed once and cannot be retrieved again.</li>
        </ul>
      </div>
    </Step>
  </Steps>
</section>

<section data-guide-section data-guide-scopes="">
  <h2>Important Notes</h2>

  <p>Key information about Airtable OAuth 2.0 authentication.</p>

  <ul>
    <li>Airtable OAuth uses PKCE (Proof Key for Code Exchange) for enhanced security</li>
    <li>Access tokens expire after 2 hours and are automatically refreshed using the refresh token</li>
    <li>Users will be prompted to select which bases the integration can access during the authorization flow</li>
    <li>If the Client Secret is lost, you can generate a new one from the integration settings page</li>
    <li>Refer to the <a href="https://airtable.com/developers/web/guides/oauth-integrations" target="_blank" rel="noopener noreferrer">Airtable OAuth documentation</a> for more details</li>
  </ul>
</section>

## Creating the StackOne Connector Profile

To create the Connector Profile in StackOne for <strong>Airtable</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>Airtable</strong></li>
      <li>Select <strong>Type</strong> as <strong>OAuth 2.0</strong></li>

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

        <ul style={{ marginLeft: '20px' }}>
          <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>Airtable</strong>.
