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

# Authentication Guide

> How to authenticate with the Plugged.in API

# API Authentication

The Plugged.in API uses Bearer token authentication to secure endpoints and identify users. This guide covers how to obtain and use API keys.

## Quick Start

<Steps>
  <Step title="Get API Key">
    Navigate to [API Keys](https://plugged.in/api-keys) in your dashboard
  </Step>

  <Step title="Create New Key">
    Click "Generate New API Key" and save it securely
  </Step>

  <Step title="Use in Requests">
    Include the key in your Authorization header:

    ```bash theme={null}
    Authorization: Bearer YOUR_API_KEY
    ```
  </Step>
</Steps>

## Authentication Methods

### Bearer Token (Recommended)

The primary authentication method for the Plugged.in API.

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://plugged.in/api/servers" \
    -H "Authorization: Bearer pk_live_abc123..."
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://plugged.in/api/servers', {
    headers: {
      'Authorization': 'Bearer pk_live_abc123...'
    }
  });
  ```

  ```python Python theme={null}
  import requests

  response = requests.get(
    'https://plugged.in/api/servers',
    headers={'Authorization': 'Bearer pk_live_abc123...'}
  )
  ```

  ```typescript TypeScript theme={null}
  import { PluggedinClient } from '@pluggedin/sdk';

  const client = new PluggedinClient({
    apiKey: 'pk_live_abc123...'
  });

  const servers = await client.servers.list();
  ```
</CodeGroup>

### OAuth 2.0

For third-party applications that need to access user data on their behalf.

#### Authorization Flow

<Steps>
  <Step title="Redirect to Authorization">
    ```
    https://plugged.in/oauth/authorize?
      client_id=YOUR_CLIENT_ID&
      redirect_uri=YOUR_CALLBACK_URL&
      response_type=code&
      scope=read:servers write:servers
    ```
  </Step>

  <Step title="User Approves">
    User logs in and approves the requested permissions
  </Step>

  <Step title="Receive Authorization Code">
    ```
    GET YOUR_CALLBACK_URL?code=auth_code_123
    ```
  </Step>

  <Step title="Exchange for Access Token">
    ```bash theme={null}
    curl -X POST "https://plugged.in/oauth/token" \
      -H "Content-Type: application/json" \
      -d '{
        "grant_type": "authorization_code",
        "code": "auth_code_123",
        "client_id": "YOUR_CLIENT_ID",
        "client_secret": "YOUR_CLIENT_SECRET",
        "redirect_uri": "YOUR_CALLBACK_URL"
      }'
    ```
  </Step>
</Steps>

**Token Response:**

```json theme={null}
{
  "access_token": "at_abc123...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "rt_xyz789...",
  "scope": "read:servers write:servers"
}
```

### Device Authorization (CLI)

For CLI tools and headless environments that cannot directly handle browser redirects. Inspired by [RFC 8628](https://datatracker.ietf.org/doc/html/rfc8628).

<Steps>
  <Step title="Initiate">
    ```bash theme={null}
    curl -s -X POST "https://plugged.in/api/cli/auth/initiate"
    ```

    **Response:**

    ```json theme={null}
    {
      "device_code": "a1b2c3...",
      "user_code": "ABCD-1234",
      "verification_url": "https://plugged.in/cli/authorize?code=ABCD-1234",
      "expires_in": 300,
      "interval": 5
    }
    ```
  </Step>

  <Step title="Direct User to Browser">
    Open `verification_url` in the user's browser. The user logs in (if needed), verifies the code, selects a Hub, and clicks **Authorize**.
  </Step>

  <Step title="Poll for Result">
    Poll every `interval` seconds (returned in step 1, default 5). Do not poll faster — requests that exceed the rate limit receive a `429` response with a `Retry-After` header.

    ```bash theme={null}
    # Wait `interval` seconds between each request
    curl -s "https://plugged.in/api/cli/auth/poll?device_code=a1b2c3..."
    ```

    **Possible statuses:**

    | Status                  | Meaning                                                        |
    | ----------------------- | -------------------------------------------------------------- |
    | `authorization_pending` | User hasn't acted yet — wait `interval` seconds and poll again |
    | `approved`              | User approved — response includes `api_key`                    |
    | `denied`                | User denied the request                                        |
    | `expired`               | Code expired (5-minute TTL)                                    |

    Stop polling on any terminal status (`approved`, `denied`, `expired`) or when `expires_in` seconds have elapsed since initiation.
  </Step>

  <Step title="Use the API Key">
    On `approved`, the response includes a ready-to-use API key:

    ```json theme={null}
    {
      "status": "approved",
      "api_key": "pg_in_..."
    }
    ```
  </Step>
</Steps>

<Info>
  The Plugged.in CLI plugin (`/pluggedin:setup`) automates this entire flow — it initiates, opens the browser, polls, and saves the key automatically.
</Info>

### Session Authentication

For browser-based applications using cookies.

```javascript theme={null}
// Login via form submission
const response = await fetch('/api/auth/login', {
  method: 'POST',
  credentials: 'include', // Important: includes cookies
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    email: 'user@example.com',
    password: 'password'
  })
});

// Subsequent requests include session cookie automatically
const servers = await fetch('/api/servers', {
  credentials: 'include'
});
```

## API Key Management

### Creating API Keys

API keys can be created through the dashboard or API.

#### Via Dashboard

1. Navigate to [API Keys](https://plugged.in/api-keys)
2. Click "Generate New API Key"
3. Set optional expiration date
4. Add description for reference
5. Copy and save the key securely

#### Via API

```bash theme={null}
POST /api/auth/keys
```

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://plugged.in/api/auth/keys" \
    -H "Authorization: Bearer YOUR_EXISTING_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Production Server",
      "expires_at": "2025-12-31T23:59:59Z",
      "scopes": ["read:servers", "write:servers"]
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://plugged.in/api/auth/keys', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_EXISTING_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      name: 'Production Server',
      expires_at: '2025-12-31T23:59:59Z',
      scopes: ['read:servers', 'write:servers']
    })
  });
  ```
</CodeGroup>

### Key Formats

API keys follow a consistent format for easy identification:

| Environment | Prefix     | Example             |
| ----------- | ---------- | ------------------- |
| Production  | `pk_live_` | `pk_live_abc123...` |
| Test        | `pk_test_` | `pk_test_xyz789...` |
| Secret      | `sk_live_` | `sk_live_def456...` |

### Key Rotation

<Warning>
  Regular key rotation is recommended for security. Rotate keys:

  * Every 90 days for production environments
  * Immediately if a key is compromised
  * When team members leave
</Warning>

#### Rotation Process

<Steps>
  <Step title="Generate New Key">
    Create a new API key while keeping the old one active
  </Step>

  <Step title="Update Applications">
    Deploy your applications with the new key
  </Step>

  <Step title="Verify">
    Ensure all systems are using the new key
  </Step>

  <Step title="Revoke Old Key">
    Delete the old key from the dashboard
  </Step>
</Steps>

### Revoking Keys

```bash theme={null}
DELETE /api/auth/keys/{key_id}
```

```bash theme={null}
curl -X DELETE "https://plugged.in/api/auth/keys/key_123" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

## Permissions & Scopes

API keys can have different permission scopes:

### Available Scopes

| Scope               | Description                    |
| ------------------- | ------------------------------ |
| `read:servers`      | Read MCP server configurations |
| `write:servers`     | Create and modify MCP servers  |
| `delete:servers`    | Remove MCP servers             |
| `read:documents`    | Access document library        |
| `write:documents`   | Upload and modify documents    |
| `read:profile`      | View profile information       |
| `write:profile`     | Update profile settings        |
| `read:collections`  | View collections               |
| `write:collections` | Create and modify collections  |
| `admin`             | Full administrative access     |

### Scope Examples

```javascript theme={null}
// Limited scope key - read only
const readOnlyClient = new PluggedinClient({
  apiKey: 'pk_live_readonly...',
  scopes: ['read:servers', 'read:documents']
});

// Full access key
const adminClient = new PluggedinClient({
  apiKey: 'pk_live_admin...',
  scopes: ['admin']
});
```

## Security Best Practices

### Storage

<Tabs>
  <Tab title="Environment Variables">
    **Recommended for server applications**

    ```bash theme={null}
    # .env file
    PLUGGEDIN_API_KEY=pk_live_abc123...
    ```

    ```javascript theme={null}
    const apiKey = process.env.PLUGGEDIN_API_KEY;
    ```
  </Tab>

  <Tab title="Secrets Manager">
    **Best for production environments**

    ```javascript theme={null}
    // AWS Secrets Manager
    const AWS = require('aws-sdk');
    const client = new AWS.SecretsManager();

    const secret = await client.getSecretValue({
      SecretId: 'pluggedin-api-key'
    }).promise();

    const apiKey = JSON.parse(secret.SecretString).apiKey;
    ```
  </Tab>

  <Tab title="Key Vault">
    **For Azure deployments**

    ```javascript theme={null}
    const { SecretClient } = require('@azure/keyvault-secrets');

    const client = new SecretClient(vaultUrl, credential);
    const secret = await client.getSecret('pluggedin-api-key');
    const apiKey = secret.value;
    ```
  </Tab>
</Tabs>

### Security Guidelines

<AccordionGroup>
  <Accordion title="Never Expose Keys in Code">
    ```javascript theme={null}
    // ❌ Bad
    const apiKey = 'pk_live_abc123...';

    // ✅ Good
    const apiKey = process.env.PLUGGEDIN_API_KEY;
    ```
  </Accordion>

  <Accordion title="Use HTTPS Only">
    Always use HTTPS when making API requests to prevent key interception.

    ```javascript theme={null}
    // ❌ Bad
    fetch('http://plugged.in/api/servers')

    // ✅ Good
    fetch('https://plugged.in/api/servers')
    ```
  </Accordion>

  <Accordion title="Implement Rate Limiting">
    Respect rate limits to avoid key suspension:

    ```javascript theme={null}
    import { RateLimiter } from 'limiter';

    const limiter = new RateLimiter({
      tokensPerInterval: 60,
      interval: 'minute'
    });

    await limiter.removeTokens(1);
    // Make API request
    ```
  </Accordion>

  <Accordion title="Monitor Key Usage">
    Track API key usage for unusual patterns:

    ```javascript theme={null}
    // Log all API requests
    client.on('request', (request) => {
      logger.info('API Request', {
        endpoint: request.url,
        timestamp: new Date()
      });
    });
    ```
  </Accordion>
</AccordionGroup>

## Error Handling

### Common Authentication Errors

| Error Code         | Description                | Solution                              |
| ------------------ | -------------------------- | ------------------------------------- |
| `401 UNAUTHORIZED` | Missing or invalid API key | Check key is included in header       |
| `403 FORBIDDEN`    | Key lacks required scope   | Generate key with correct permissions |
| `429 RATE_LIMITED` | Too many requests          | Implement exponential backoff         |
| `410 GONE`         | API key revoked            | Generate a new API key                |

### Error Response Example

```json theme={null}
{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Invalid API key provided",
    "details": {
      "key_prefix": "pk_test_",
      "hint": "Ensure you're using a production key for this environment"
    }
  }
}
```

### Handling Errors

```javascript theme={null}
try {
  const response = await fetch('https://plugged.in/api/servers', {
    headers: {
      'Authorization': 'Bearer ' + apiKey
    }
  });

  if (!response.ok) {
    const error = await response.json();

    switch (error.error.code) {
      case 'UNAUTHORIZED':
        // Refresh token or prompt for new key
        break;
      case 'RATE_LIMITED':
        // Wait and retry with exponential backoff
        await sleep(Math.pow(2, retryCount) * 1000);
        break;
      default:
        throw new Error(error.error.message);
    }
  }
} catch (error) {
  console.error('API request failed:', error);
}
```

## Testing

### Test API Keys

Use test API keys for development and testing:

```javascript theme={null}
const client = new PluggedinClient({
  apiKey: process.env.NODE_ENV === 'production'
    ? 'pk_live_abc123...'
    : 'pk_test_xyz789...'
});
```

### Mock Authentication

For unit tests, mock the authentication:

```javascript theme={null}
// Jest example
jest.mock('@pluggedin/sdk', () => ({
  PluggedinClient: jest.fn().mockImplementation(() => ({
    servers: {
      list: jest.fn().mockResolvedValue([
        { id: '1', name: 'Test Server' }
      ])
    }
  }))
}));
```

## Migration Guide

### From API v1 to v2

If you're migrating from an older API version:

<Steps>
  <Step title="Update Authentication Header">
    ```javascript theme={null}
    // Old (v1)
    headers: { 'X-API-Key': apiKey }

    // New (v2)
    headers: { 'Authorization': 'Bearer ' + apiKey }
    ```
  </Step>

  <Step title="Update Endpoints">
    ```javascript theme={null}
    // Old (v1)
    /api/v1/servers

    // New (v2)
    /api/servers
    ```
  </Step>

  <Step title="Handle New Response Format">
    Responses now include consistent error objects and pagination
  </Step>
</Steps>

## Support

For authentication issues or questions:

* **Documentation**: [API Reference](/api/reference)
* **Status Page**: [status.plugged.in](https://status.plugged.in)
* **Support Email**: [api-support@plugged.in](mailto:api-support@plugged.in)
* **GitHub Issues**: [Report issues](https://github.com/VeriTeknik/pluggedin-app/issues)
