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

# Authentication

> API credentials and HMAC signing for Emerge Link

Emerge uses two authentication mechanisms:

1. **API Token** - Bearer token for API calls
2. **HMAC Signature** - Signed URLs for the consent flow

## API Token

Use your API token for server-to-server API calls. Include it in the `Authorization` header:

```bash theme={null}
curl -X GET 'https://link.emergedata.ai/consent/status/psub_c3d4e5f6789012345678901234abcdef' \
  -H 'Authorization: Bearer your_api_token'
```

<Warning>
  Never expose your API token in client-side code. All API calls should be made from your backend.
</Warning>

## HMAC Signing

Consent flow URLs are signed with HMAC-SHA256 to prevent tampering. The signature validates that:

* The URL parameters haven't been modified
* The request originated from your application
* The link hasn't expired (30-day validity)

### Signature algorithm

1. Collect all URL parameters (except `signature`)
2. Sort parameters alphabetically by key
3. Join as `key=value&key=value` (raw values, not URL-encoded)
4. Generate HMAC-SHA256 using your signing secret
5. Append signature as hex string

### Parameters to sign

| Parameter      | Required | Description                                           |
| -------------- | -------- | ----------------------------------------------------- |
| `client_id`    | Yes      | Your client identifier                                |
| `redirect_uri` | Yes      | Callback URL                                          |
| `state`        | Yes      | CSRF protection token                                 |
| `timestamp`    | Yes      | ISO 8601 timestamp (e.g., `2024-01-15T10:30:00.000Z`) |
| `uid`          | No       | Your user identifier                                  |
| `flow_config`  | No       | Named configuration for custom branding               |

### Example signature generation

<CodeGroup>
  ```typescript TypeScript theme={null}
  import crypto from 'crypto';

  function signParams(params: Record<string, string>, signingSecret: string): string {
    // Sort parameters alphabetically
    const sortedKeys = Object.keys(params).sort();

    // Join as raw key=value pairs (NOT URL-encoded)
    const signatureBase = sortedKeys
      .map(key => `${key}=${params[key]}`)
      .join('&');

    // Generate HMAC-SHA256
    return crypto
      .createHmac('sha256', signingSecret)
      .update(signatureBase)
      .digest('hex');
  }

  // Usage
  const params = {
    client_id: 'your_client_id',
    redirect_uri: 'https://yourapp.com/callback',
    state: 'random_state_value',
    timestamp: new Date().toISOString(),
    uid: 'psub_c3d4e5f6789012345678901234abcdef'
  };

  const signature = signParams(params, 'your_signing_secret');
  ```

  ```python Python theme={null}
  import hmac
  import hashlib
  from datetime import datetime, timezone

  def sign_params(params: dict, signing_secret: str) -> str:
      # Sort parameters alphabetically
      sorted_items = sorted(params.items())

      # Join as raw key=value pairs (NOT URL-encoded)
      signature_base = '&'.join(f'{k}={v}' for k, v in sorted_items)

      # Generate HMAC-SHA256
      return hmac.new(
          signing_secret.encode(),
          signature_base.encode(),
          hashlib.sha256
      ).hexdigest()

  # Usage
  params = {
      'client_id': 'your_client_id',
      'redirect_uri': 'https://yourapp.com/callback',
      'state': 'random_state_value',
      'timestamp': datetime.now(timezone.utc).isoformat().replace('+00:00', 'Z'),
      'uid': 'psub_c3d4e5f6789012345678901234abcdef'
  }

  signature = sign_params(params, 'your_signing_secret')
  ```
</CodeGroup>

<Warning>
  The signature base uses **raw parameter values**, not URL-encoded values. URL encoding is only applied when constructing the final URL.
</Warning>

## Credential management

### Obtaining credentials

1. Sign in to [The Control Room](https://dashboard.emergedata.ai)
2. Navigate to **Settings** → **API Keys**
3. Generate or view your credentials

You'll receive:

* **Client ID** - Public identifier for your application
* **Signing Secret** - Private key for HMAC signatures (keep secure)
* **API Token** - Bearer token for API calls

### Rotating credentials

To rotate your credentials:

1. Go to **Settings** → **API Keys** in the Control Room
2. Click **Regenerate Keys**
3. A one-time retrieval link is emailed to the admin
4. The link expires after 60 minutes

<Note>
  After regeneration, existing signed links remain valid for their 30-day period. Only new links need the new secret.
</Note>

## Security best practices

<AccordionGroup>
  <Accordion title="Store secrets securely">
    Use environment variables or a secrets manager (AWS Secrets Manager, HashiCorp Vault). Never commit secrets to version control.
  </Accordion>

  <Accordion title="Validate state parameter">
    Always verify the `state` parameter in callbacks matches what you sent. This prevents CSRF attacks.
  </Accordion>

  <Accordion title="Use HTTPS redirect URIs">
    Only HTTPS redirect URIs are allowed in production. This ensures the callback is encrypted.
  </Accordion>

  <Accordion title="Implement token refresh">
    API tokens don't expire, but rotate them periodically as a security practice.
  </Accordion>
</AccordionGroup>
