# Investigate Auth — Custom

## Purpose

Extract every field needed to generate a Falcon `custom` auth config for one specific non-OAuth2 authentication type. Called once per custom auth type — if a provider supports both `api_key` and `basic`, this skill is invoked twice with different `auth_type` inputs.

---

## Input

| Parameter | Required | Values |
|-----------|----------|--------|
| `provider` | ✅ | Provider slug |
| `auth_docs_url` | ✅ | URL of the auth documentation page |
| `auth_type` | ✅ | One of: `api_key` \| `personal_access_token` \| `basic` \| `bearer` \| `header` |

---

## Fetch Strategy

Follow the shared fallback chain in `../shared/auth-investigation-common.md → Fetch strategy` (WebFetch → crwl → Playwright → GitHub search, with soft-404 detection).

GitHub search queries for this skill (step 4 — always run):
```
WebSearch("<provider> api key header authentication site:github.com")
WebSearch("<provider> authorization bearer token site:github.com")
WebSearch("<provider> api credentials connector site:github.com")
```

---

## What to Extract

Focus extraction on fields relevant to the given `auth_type`:

| `auth_type` | `authorization.type` | What to look for |
|-------------|---------------------|-----------------|
| `api_key` | `api_key_header` | Header name (e.g. `X-API-Key`), key format, where to find the key |
| `personal_access_token` | `bearer` | Token prefix, token format, how to generate a PAT |
| `basic` | `basic` | Username field, password field, whether username is email/ID |
| `bearer` | `bearer` | Token prefix, token format, where to get the static token |
| `header` | `api_key_header` | Custom header name, value format |

### Scopes — extract only if the provider documents them:

Some providers allow scope selection when generating API keys, PATs, or tokens (e.g. GitHub PATs, Notion integrations). Check the token creation docs specifically, then run the full 4-step search strategy in `../shared/auth-investigation-common.md → Scope extraction search strategy` before setting `scopes: []` and `scope_strategy: null`.

### Base URL pattern:

- **Static**: Same for all accounts → `"is_dynamic": false, "static_url": "https://..."`
- **Dynamic/per-tenant**: Changes per account → `"is_dynamic": true, "dynamic_expression": "${credentials.apiUrl}/..."`

### Config fields — for each credential field the user must provide:

Capture the properties in `../shared/auth-investigation-common.md → Credential field properties` (`key`, `label`, `type`, `required`, `secret`, `placeholder`, `description`, `where_to_find`).

---

## Output File

**Path:** `.connector-dev/<provider>/research/auth/auth_<auth_type>.json`

e.g. `.connector-dev/asana/research/auth/auth_api_key.json`, `.connector-dev/asana/research/auth/auth_basic.json`

```json
{
  "auth_type": "api_key",
  "supported": true,
  "label": "API Key",
  "auth_docs_url": "<auth docs URL fetched>",

  "authorization": {
    "type": "api_key_header",
    "note": "bearer | api_key_header | basic | none",

    "bearer": {
      "token_expression": "$.credentials.apiKey"
    },

    "api_key_header": {
      "header_name": "X-API-Key",
      "header_value_template": "{apiKey}",
      "expression": "$.credentials.apiKey"
    },

    "basic": {
      "username_expression": "$.credentials.username",
      "password_expression": "$.credentials.password"
    }
  },

  "config_fields": [
    {
      "key": "apiKey",
      "label": "API Key",
      "type": "password",
      "required": true,
      "secret": true,
      "placeholder": "sk-xxxxxxxxxxxx",
      "description": "Your API key. Found in Settings > Developer > API Keys.",
      "where_to_find": "Settings > Developer > API Keys"
    }
  ],

  "scopes": [
    // [] if provider has no scope selection for this auth type
    {
      "name": "repo",
      "description": "Full access to repositories",
      "required": false,
      "category": "repositories",
      "tier_restriction": null
    }
  ],

  "scope_strategy": null,  // null if no scopes; "required_plus_optional" | "single_list" | "static_in_config" if scopes exist

  "base_url": {
    "is_dynamic": false,
    "static_url": "https://api.provider.com/v2",
    "dynamic_expression": null,
    "note": "Set is_dynamic=true and dynamic_expression if URL varies per account"
  },

  "environments": [
    { "key": "production", "name": "Production" },
    { "key": "sandbox", "name": "Sandbox", "base_url_override": null }
  ],

  "rate_limit": {
    "requests_per_second": null,
    "requests_per_minute": null,
    "retry_after_header": null,
    "notes": null
  },

  "quirks": [],
  "github_findings": []
}
```

**Rules:**
- Set `auth_type` in the output JSON to the exact input value passed in
- Only populate the authorization sub-block matching the detected mechanism — leave others as `null`
- `environments` — only add sandbox entry if provider documents a separate sandbox environment/URL
- `where_to_find` — always extract even if not in main docs; check GitHub findings
- Never infer placeholder — use exactly the format the provider shows in examples
- `scopes` — check the token/key creation docs specifically (e.g. GitHub PAT scope selection); set `[]` if not present
- `scope_strategy` — set `null` when `scopes` is empty

---

## Anti-Patterns

Shared anti-patterns (scope handling, `where_to_find`, `placeholder`, `secret` typing, sandbox URLs) live in `../shared/auth-investigation-common.md → Shared anti-patterns`. Custom-auth-specific:

- ❌ Use `authorization.type: "none"` without documenting the actual mechanism in `quirks`
- ❌ Omit `auth_type` from the output JSON — must match the input value exactly
- ❌ Assume custom auth never has scopes — always check token/key creation docs
