# Custom Authentication

Configure custom authentication for Falcon connectors. Use for static credentials like API keys, Basic Auth, and Bearer tokens that don't require token exchange.

## When to Use Custom Auth

Use `type: custom` when the provider uses **static credentials with NO token exchange**.

**Decision Guide:**
- ✅ No token exchange (static API key, token) → `custom`
- ✅ Basic authentication (username + password) → `custom`
- ✅ Bearer token provided by user → `custom`
- ✅ Custom headers (not Authorization) → `custom` with `authorization.type: none`
- ❌ Token exchange via endpoint → read `references/auth-oauth2.md` instead

**⚠️ CRITICAL:** Analyze the actual authentication flow. If there's any token exchange endpoint, use OAuth 2.0 instead.

## Custom Auth Schema

```yaml
authentication:
  - custom:
      type: custom
      label: API Key                      # Display name in UI

      # Authorization configuration
      authorization:
        type: bearer      # bearer | basic | apiKey | none
        # Configuration depends on type (see below)

      # Config fields (T2-facing: end user credentials)
      configFields:
        - key: accessToken
          label: API Token
          type: password
          required: true
          secret: true
          placeholder: sk_live_abc123xyz
          description: Your API token from provider settings

      # Optional: Environment configuration
      environments:
        - key: production
          name: Production
        - key: sandbox
          name: Sandbox

      # Optional: Connection test actions
      testActions:
        - action: list_users
          required: true

      # Optional: Support documentation
      support:
        description: API Key authentication description
        guides:
          config:
            # Configuration guide for end users
```

## Authorization Types

### 1. Bearer Token

Most common for API keys. Adds `Authorization: Bearer <token>` header.

```yaml
authorization:
  type: bearer
  token: $.credentials.accessToken
  includeBearer: true           # true: "Bearer <token>" | false: "<token>"
```

**Generated header:**
```
Authorization: Bearer sk_live_abc123xyz
```

**Example providers**: Stripe, GitHub Personal Access Token, Linear

### 2. Basic Authentication

Encodes username:password as Base64. Adds `Authorization: Basic <base64>` header.

```yaml
authorization:
  type: basic
  username: $.credentials.email
  password: $.credentials.accessToken
```

**Generated header:**
```
Authorization: Basic <base64(email:accessToken)>
```

**Example providers**: Jira (email + API token), Atlassian

### 3. API Key Header

Custom header name with API key value.

```yaml
authorization:
  type: apiKey
  key: X-API-Key                # Header name
  value: $.credentials.apiKey   # Header value
```

**Generated header:**
```
X-API-Key: abc123xyz
```

**Example providers**: APIs with custom header requirements

### 4. No Authorization Header

When credentials are passed via query parameters, request body, or custom headers in each action.

```yaml
authorization:
  type: none
```

**Use cases:**
- API key in query parameter: `?api_key=xxx`
- Credentials in request body
- Custom headers defined per-action (see the `step-function-request.md` in `references/`)

**⚠️ IMPORTANT**: With `type: none`, you must add authentication parameters to EVERY action's request step using `args`.

## Config Fields

End user credentials and configuration:

```yaml
configFields:
  - key: accessToken
    label: API Token
    type: password              # password | text
    required: true
    secret: true                # true: masked in UI
    placeholder: sk_live_abc123xyz
    description: Generate via Settings > API > Create Token
    tooltip: Keep secure, won't be shown again

  - key: email
    label: Email Address
    type: text
    required: true
    secret: false
    placeholder: user@company.com
    description: Your account email address

  - key: domain
    label: Subdomain
    type: text
    required: true
    secret: false
    placeholder: company
    description: Your account subdomain (e.g., company.provider.com)
```

**Field types:**
- `password`: Masked input, stored securely
- `text`: Plain text input
- `number`: Numeric input
- `select`: Dropdown selection (requires `options` array with `label`/`value` pairs)

**Security:**
- Set `secret: true` for sensitive data (API keys, tokens, passwords)
- Set `secret: false` for non-sensitive data (email, domain, workspace ID)

> **Region / Data Center / Server Location:** If provider has geographic regions, add as `configField` or `setupField` (based on research data — who sets the region: T1 admin → setupFields, T2 user → configFields) with `type: select` — NEVER as `environments` entries. Use provider's exact terminology for `label`. See `build-connector-config.md` section 2a for patterns.

## Environments

Support multiple environments (production, sandbox, staging). Environments are deployment stages ONLY — `production`, `sandbox`, `staging`. Region/location/datacenter values do NOT go here — those are `configFields`.

```yaml
environments:
  - key: production
    name: Production
    baseUrl: https://api.provider.com        # Optional override

  - key: sandbox
    name: Sandbox
    baseUrl: https://sandbox-api.provider.com
```

**Per-environment base URLs** override the main `baseUrl` in connector config.

## Test Actions

Validate credentials when user connects:

```yaml
testActions:
  - action: {action_id}   # e.g. list_users, get_current_user, get_account
    required: true            # Must pass for connection
```

## Support Documentation

### Config Guides

Guide end users through finding and creating credentials:

```yaml
support:
  description: API Key provides quick authentication without OAuth flow.
  guides:
    config:
      warning: "Keep your API key secure and never share it publicly."
      sections:
        - title: Prerequisites
          content: |
            Verify you have the necessary access before starting.
          list:
            - An active account with appropriate permissions
            - Access to account settings

        - title: Generate API Key
          content: |
            Create an API key to authenticate requests.
          steps:
            - title: Access API settings
              content: |
                Navigate to your account settings.
              list:
                - Sign in to your account
                - Click Settings > API
                - Click "Create new API key"

            - title: Copy API key
              content: |
                Save the API key securely.
              list:
                - Copy the generated API key
                - Store it securely for use later
                - The key is displayed only once

        - title: Find your Workspace ID
          content: |
            Locate your workspace identifier.
          list:
            - Check your browser URL when logged in
            - "Format: https://app.provider.com/workspace/{id}"
```

## Complete Examples

### Bearer Token (Stripe-style)

```yaml
authentication:
  - custom:
      type: custom
      label: API Key
      authorization:
        type: bearer
        token: $.credentials.apiKey
        includeBearer: true
      configFields:
        - key: apiKey
          label: API Key
          type: password
          required: true
          secret: true
          placeholder: sk_live_abc123xyz
          description: Your API key from Stripe Dashboard
      environments:
        - key: production
          name: Production
      testActions:
        - action: list_customers
          required: true
```

### Basic Auth (Jira-style)

```yaml
authentication:
  - custom:
      type: custom
      label: API Key
      authorization:
        type: basic
        username: $.credentials.email
        password: $.credentials.accessToken
      configFields:
        - key: email
          label: Email Address
          type: text
          required: true
          secret: false
          placeholder: user@company.com
          description: Your Jira account email

        - key: accessToken
          label: API Token
          type: password
          required: true
          secret: true
          placeholder: ATATT3xFfGF0aQNaJZQ9JtSvQ
          description: Generate via Atlassian Account Settings > Security > API tokens

        - key: domain
          label: Jira Domain
          type: text
          required: true
          secret: false
          placeholder: company
          description: Your Jira domain (company.atlassian.net)
      environments:
        - key: production
          name: Production
      testActions:
        - action: list_users
          required: true
```

### Custom Header (X-API-Key)

```yaml
authentication:
  - custom:
      type: custom
      label: API Key
      authorization:
        type: apiKey
        key: X-API-Key
        value: $.credentials.apiKey
      configFields:
        - key: apiKey
          label: API Key
          type: password
          required: true
          secret: true
          placeholder: abc123xyz
          description: Your API key from account settings
      testActions:
        - action: list_resources
          required: true
```

### No Authorization Header (Query Parameter)

```yaml
authentication:
  - custom:
      type: custom
      label: API Key
      authorization:
        type: none          # No Authorization header
      configFields:
        - key: apiKey
          label: API Key
          type: password
          required: true
          secret: true
      testActions:
        - action: list_users
          required: true
```

**With `type: none`, add credentials to each action:**

```yaml
steps:
  - stepId: fetch_users
    description: Fetch users with API key in query
    stepFunction:
      functionName: request
      parameters:
        url: /users
        method: get
        args:
          - name: api_key
            value: $.credentials.apiKey
            in: query              # Add to query string
```

### Multiple Environments with Different Base URLs

```yaml
authentication:
  - custom:
      type: custom
      label: API Key
      authorization:
        type: bearer
        token: $.credentials.apiKey
        includeBearer: true
      configFields:
        - key: apiKey
          label: API Key
          type: password
          required: true
          secret: true
      environments:
        - key: production
          name: Production
          baseUrl: https://api.provider.com

        - key: sandbox
          name: Sandbox
          baseUrl: https://sandbox.api.provider.com

        - key: staging
          name: Staging
          baseUrl: https://staging.api.provider.com
      testActions:
        - action: get_account
          required: true
```

### Dynamic Base URL with Subdomain

```yaml
# In main connector config
baseUrl: https://${credentials.domain}.api.provider.com

authentication:
  - custom:
      type: custom
      label: API Key
      authorization:
        type: bearer
        token: $.credentials.apiKey
        includeBearer: true
      configFields:
        - key: apiKey
          label: API Key
          type: password
          required: true
          secret: true

        - key: domain
          label: Subdomain
          type: text
          required: true
          secret: false
          placeholder: company
          description: Your account subdomain
      testActions:
        - action: get_account
          required: true
```

## Multi-Auth Connectors

Some connectors support both custom auth and OAuth 2.0:

> **The map keys (`custom:`/`oauth2:` below) are each block's identifier, not fixed
> keywords** — gates A9/B6 match them against the researched `authMechanisms[].type`, so
> name each after its researched type verbatim (e.g. `- personal_access_token:`).

```yaml
authentication:
  - custom:
      type: custom
      label: Personal Access Token
      # Custom auth configuration

  - oauth2:
      type: oauth2
      label: OAuth 2.0
      # OAuth 2.0 configuration (see auth-oauth2 skill)
```

**Best practices:**
- List simpler auth method first (custom before OAuth)
- Use clear labels to differentiate ("Personal Access Token" vs "OAuth 2.0")
- Provide guidance in support docs about when to use each

## Critical Rules

### MUST DO:
- ✅ Use `custom` for static credentials (no token exchange)
- ✅ Set `secret: true` for sensitive fields (API keys, passwords, tokens)
- ✅ Use appropriate authorization type (bearer, basic, apiKey, none)
- ✅ Add test actions to validate credentials
- ✅ Provide clear guidance in support docs
- ✅ Use `type: none` when auth is in query/body/custom headers
- ✅ Reference credentials with JSONPath: `$.credentials.fieldName`

### MUST NOT:
- ❌ Use custom auth for OAuth flows (use `auth-oauth2` instead)
- ❌ Hardcode credentials in configuration
- ❌ Set `secret: false` for API keys, passwords, tokens
- ❌ Skip test actions
- ❌ Forget to add auth params to actions when using `type: none`
- ❌ Copy patterns from existing connectors instead of following this skill — existing connectors may use outdated or workaround patterns

### Source of Truth Rule
**This skill is the primary source of truth for custom authentication configuration.** Only reference existing connectors in `src/configs/` when this skill is ambiguous or incomplete for a specific case, and only to verify — not to copy wholesale. When in doubt, follow the examples in this skill exactly.

---

## Related Skills

- **connector-patterns**: Base connector structure and corpus-mined conventions
- **auth-oauth2**: OAuth 2.0 authentication
- **step-function-request** (`build/build-actions`): Adding auth to request steps with `args`
- **connector-patterns/references/schema-vs-corpus.md**: Expression formats for credentials

---

**Remember**: Custom auth is for static credentials. If there's token exchange, use OAuth 2.0 (auth-oauth2 skill).
