# Authentication

This document covers the authentication methods for Sling API specifications. For the basic structure, see [Structure](/concepts/api-specs/structure.md).

Sling supports several authentication methods, configured under the `authentication` key.

> ⚠️ **Important:** It's best practice to use environment variables or secrets for sensitive values instead of hardcoding them.

## Managing Secrets and Environment Variables

Sling provides flexible ways to manage sensitive authentication data through environment variables and the `env.yaml` file. Here's how to configure them:

### Using the env.yaml File

The primary method for managing secrets is through the [`env.yaml`](/sling-cli/environment.md) file located at `~/.sling/env.yaml`. When defining API connections, you can specify secrets that will be available to your API specs.

```yaml
# ~/.sling/env.yaml
connections:
  my_api:
    type: api
    spec: file:///path/to/my_api.spec.yaml
    secrets:
      api_key: "your-secret-api-key"
      client_id: "your-oauth-client-id"
      client_secret: "your-oauth-client-secret"
      username: "your-username"
      password: "your-password"
      
  github_api:
    type: api
    spec: github
    secrets:
      token: "ghp_xxxxxxxxxxxxxxxxxxxx"
      
  stripe_api:
    type: api
    spec: stripe
    secrets:
      api_key: "sk_test_xxxxxxxxxxxxxxxxxxxx"
```

You'll be able to access the secrets values via the `{secrets.var_name}` expression.

```yaml
# In your API spec
defaults:
  request:
    headers:
      Authorization: "Bearer {secrets.api_key}"
```

### Using Environment Variables

You can also provide secrets via environment variables. In your API spec, use the `{env.VARIABLE_NAME}` syntax:

```bash
# Set environment variables
export API_USERNAME="myuser"
export API_PASSWORD="mypassword"
```

```yaml
# In your API spec
authentication:
  type: "basic"
  username: "{env.API_USERNAME}"
  password: "{env.API_PASSWORD}"
```

## Authentication Methods

Now that you understand how to manage secrets, here are the different authentication methods you can configure:

### No Authentication

```yaml
# Simply omit the authentication block for APIs that don't require authentication
```

### Static Header Authentication

For APIs that require headers for authentication (e.g., API keys, bearer tokens):

```yaml
authentication:
  type: "static"
  headers:
    Authorization: "Bearer {secrets.api_token}"
```

This is ideal for:

* API keys passed in headers (e.g., `X-API-Key: your-key`)
* Bearer tokens (e.g., `Authorization: Bearer your-token`)
* Custom authentication headers
* Multiple authentication headers

**Examples:**

```yaml
# API Key in custom header
authentication:
  type: "static"
  headers:
    X-API-Key: "{secrets.api_key}"

# Bearer token
# we can omit `type: static` and only specify `headers`
authentication:
  headers:
    Authorization: "Bearer {secrets.access_token}"

# Multiple headers
authentication:
  headers:
    Authorization: "Bearer {secrets.access_token}"
    X-API-Key: "{secrets.api_key}"
    X-Tenant-ID: "{secrets.tenant_id}"
```

**Shorthand Syntax:**

When only `headers` are provided without any other authentication configuration, the type defaults to `static`:

```yaml
# This is equivalent to type: "static"
authentication:
  headers:
    Authorization: "Bearer {secrets.api_token}"
```

> 📝 **Note:** For dynamic token retrieval (e.g., login flow), use the `sequence` authentication type instead.

### Basic Auth

```yaml
authentication:
  type: "basic"
  username: "{secrets.username}"
  password: "{secrets.password}"
```

### OAuth2 Authentication

For OAuth2 flows, use the `oauth2` type. Sling supports three OAuth2 flows:

| Flow                 | Use Case                             | Interactive             |
| -------------------- | ------------------------------------ | ----------------------- |
| `client_credentials` | Server-to-server, machine-to-machine | No                      |
| `authorization_code` | User-facing apps, browser-based auth | Yes                     |
| `device_code`        | CLI tools, headless environments     | Yes (on another device) |

**Full Property Reference:**

```yaml
authentication:
  type: "oauth2"
  flow: "client_credentials"  # client_credentials|authorization_code|device_code
  client_id: "{secrets.client_id}"
  client_secret: "{secrets.client_secret}"
  authentication_url: "https://api.example.com/oauth/token"      # Token endpoint (required)
  authorization_url: "https://api.example.com/oauth/authorize"   # Auth endpoint (for authorization_code)
  device_auth_url: "https://api.example.com/oauth/device/code"   # Device auth endpoint (for device_code)
  redirect_uri: "http://localhost:8080/callback"                 # Redirect URI (for authorization_code)
  scopes:
    - "read:data"
    - "write:data"
```

> **Token Persistence:** Sling automatically stores OAuth tokens in `~/.sling/api/tokens/{connection_name}.json` and refreshes them when they expire. You don't need to manage token refresh manually.

> **PKCE Support:** For public clients (when `client_secret` is empty), Sling automatically enables PKCE (Proof Key for Code Exchange) for added security.

**Client Credentials Flow (Server-to-Server):**

The most common flow for automated data pipelines. No user interaction required.

```yaml
authentication:
  type: "oauth2"
  flow: "client_credentials"
  client_id: "{secrets.client_id}"
  client_secret: "{secrets.client_secret}"
  authentication_url: "https://api.example.com/oauth/token"
  scopes:
    - "read:data"
```

**Authorization Code Flow (Browser-Based):**

For user-interactive authentication. Sling opens a browser for authorization and handles the callback automatically.

```yaml
authentication:
  type: "oauth2"
  flow: "authorization_code"
  client_id: "{secrets.client_id}"
  client_secret: "{secrets.client_secret}"
  authentication_url: "https://api.example.com/oauth/token"
  authorization_url: "https://api.example.com/oauth/authorize"
  scopes:
    - "read:data"
```

**Device Code Flow (Headless/CLI):**

For environments without a browser. Sling displays a URL and code for the user to enter on another device.

```yaml
authentication:
  type: "oauth2"
  flow: "device_code"
  client_id: "{secrets.client_id}"
  authentication_url: "https://api.example.com/oauth/token"
  device_auth_url: "https://api.example.com/oauth/device/code"
  scopes:
    - "read:data"
```

### AWS Signature V4 Authentication

For AWS services that require Signature V4 authentication (e.g., S3, AppSync, API Gateway):

```yaml
authentication:
  type: "aws-sigv4"
  aws_service: "execute-api"  # The AWS service name (e.g., s3, execute-api, appsync)
  aws_region: "{env.AWS_REGION}"
  aws_access_key_id: "{secrets.aws_access_key_id}"
  aws_secret_access_key: "{secrets.aws_secret_access_key}"
  aws_session_token: "{secrets.aws_session_token}"  # Optional, for temporary credentials
  aws_profile: "{env.AWS_PROFILE}"  # Optional, use AWS profile instead of explicit keys
```

> 📝 **Note:** For AWS authentication, you can use either explicit credentials (`aws_access_key_id`, `aws_secret_access_key`) or AWS profiles (`aws_profile`). The AWS SDK credential chain is also supported.

### HMAC Authentication

For APIs that require HMAC (Hash-based Message Authentication Code) request signing, such as cryptocurrency exchanges (Kraken, Binance) or custom enterprise APIs:

```yaml
authentication:
  type: "hmac"
  algorithm: "sha256"  # sha256 or sha512
  secret: "{secrets.api_secret}"
  secret_encoding: "hex"  # Optional: "hex", "base64", or "raw" (default)
  signing_string: "{http_method}{http_path}{unix_time}{http_body_sha256}"
  request_headers:
    X-Signature: "{signature}"
    X-Timestamp: "{unix_time}"
    X-API-Key: "{secrets.api_key}"
  nonce_length: 16  # Optional: generates random nonce (in bytes)
```

**How HMAC Works:**

1. A signing string is constructed from request components (method, path, timestamp, body hash, etc.)
2. The string is signed using HMAC-SHA256 or HMAC-SHA512 with your secret key
3. The signature and related headers are automatically added to each request

**Secret Encoding:**

Some APIs provide secrets in encoded formats (hex or base64) that must be decoded to raw bytes before signing. Use `secret_encoding` (*v1.5.6+*) to specify how to decode the secret:

* `"raw"` or `""` (default) - Use secret as-is (plain string)
* `"hex"` - Decode secret from hexadecimal string to bytes
* `"base64"` - Decode secret from base64 string to bytes

**Available Variables for Signing:**

* `http_method` - HTTP method (GET, POST, etc.)
* `http_path` - Request path with query parameters
* `http_query` - Canonical query string (sorted alphabetically by key)
* `http_headers` - Canonical headers (lowercase, sorted, newline-separated)
* `http_body_raw` - Raw request body as string
* `http_body_md5` - MD5 hash of request body (hex-encoded)
* `http_body_sha1` - SHA1 hash of request body (hex-encoded)
* `http_body_sha256` - SHA256 hash of request body (hex-encoded)
* `http_body_sha512` - SHA512 hash of request body (hex-encoded)
* `unix_time` - Unix timestamp in seconds
* `unix_time_ms` - Unix timestamp in milliseconds
* `date_iso` - ISO 8601 formatted date (e.g., "2023-10-31T15:30:32Z")
* `date_rfc1123` - RFC 1123 formatted date (e.g., "Tue, 31 Oct 2023 15:30:32 GMT")
* `nonce` - Random hex string (if `nonce_length` is set)
* `signature` - Computed HMAC signature (hex-encoded, only available in `request_headers`)

**Example: Kraken-style Authentication**

```yaml
authentication:
  type: "hmac"
  algorithm: "sha256"
  secret: "{secrets.api_secret}"
  signing_string: "{http_method}{http_path}{nonce}{http_body_sha256}"
  request_headers:
    API-Key: "{secrets.api_key}"
    API-Sign: "{signature}"
    API-Nonce: "{nonce}"
  nonce_length: 16
```

**Example: Hex-encoded Secret**

Some APIs provide secrets as hex strings that must be decoded before signing:

```yaml
authentication:
  type: "hmac"
  algorithm: "sha256"
  secret: "{secrets.api_secret}"
  secret_encoding: "hex"
  signing_string: "{http_body_raw}"
  request_headers:
    Content-Type: "application/json"
    X-API-Key: "{secrets.api_key}"
    X-API-Signature: "{signature}"
```

> 📝 **Note:** The `signing_string` and `request_headers` templates support all Sling template variables including `{secrets.*}`, `{env.*}`, and `{state.*}`.

### Sequence Authentication (Custom Workflows)

For APIs requiring a custom authentication sequence (e.g., multi-step login), use the `sequence` type. This allows defining a series of API calls to obtain authentication tokens or session data.

```yaml
authentication:
  type: "sequence"
  expires: 3600   # re-auth every 1 hr
  sequence:
    - request:
        url: "/login"
        method: POST
        payload:
          site_id: "{secrets.site_id}"
          user_id: "{secrets.user_id}"
          password: "{secrets.password}"
      response:
        processors:
          - expression: "response.json.token"
            output: "state.token"   # you can use this in you main request block
            aggregation: last
```

This performs a login request and extracts the token into `state.token` for use in subsequent requests. See [Requests & Responses](https://github.com/slingdata-io/sling-docs/blob/master/concepts/api/requests.md) for more on sequences.

## Endpoint-Level Authentication

By default, all endpoints use the authentication configured at the spec level. However, individual endpoints can override or disable authentication.

### Overriding Authentication

An endpoint can specify its own authentication that overrides the spec-level configuration:

```yaml
authentication:
  type: "basic"
  username: "{secrets.username}"
  password: "{secrets.password}"

endpoints:
  # Uses spec-level basic auth
  users:
    request:
      url: "{state.base_url}/users"

  # Uses its own OAuth2 auth instead
  admin_data:
    authentication:
      type: "oauth2"
      flow: "client_credentials"
      client_id: "{secrets.admin_client_id}"
      client_secret: "{secrets.admin_client_secret}"
      authentication_url: "https://api.example.com/oauth/token"
    request:
      url: "{state.base_url}/admin/data"
```

### Disabling Authentication

Some endpoints (like health checks or public data) may not require authentication. Set `authentication: null` to disable it:

```yaml
authentication:
  type: "oauth2"
  # ... OAuth config for most endpoints

endpoints:
  # No authentication needed for health check
  health:
    authentication: null
    request:
      url: "{state.base_url}/health"

  # Uses spec-level OAuth2
  protected_data:
    request:
      url: "{state.base_url}/data"
```

## Authentication Expiry

The `expires` property can be used with any authentication type to force re-authentication after a specified number of seconds. This is useful when tokens or sessions have a fixed lifetime.

```yaml
authentication:
  type: "basic"
  username: "{secrets.username}"
  password: "{secrets.password}"
  expires: 3600  # Re-authenticate every hour
```

When authentication expires, Sling automatically re-authenticates before the next request. This happens transparently without interrupting data extraction.

## Authentication Method Comparison

| Method      | Best For                          | Auto-Refresh       | Interactive     |
| ----------- | --------------------------------- | ------------------ | --------------- |
| `static`    | API keys, bearer tokens           | N/A                | No              |
| `basic`     | Username/password APIs            | N/A                | No              |
| `oauth2`    | Modern APIs, delegated auth       | Yes                | Depends on flow |
| `aws-sigv4` | AWS services                      | Yes                | No              |
| `hmac`      | Crypto exchanges, signed requests | N/A                | No              |
| `sequence`  | Custom auth workflows             | No (use `expires`) | No              |


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.slingdata.io/concepts/api-specs/authentication.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
