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

# Authentication Guide

> Complete guide to authenticating with the Shipstar API

## Overview

The Shipstar API uses Bearer token authentication. There are two types of tokens depending on which API you're using:

| API                                                          | Token Type        | How to Get                               |
| ------------------------------------------------------------ | ----------------- | ---------------------------------------- |
| Internal API (`/api/internal/`)                              | JWT session token | Login via `/api/internal/auth/jwt/login` |
| Public API (`/api/v1/me`)                                    | API key           | Create in the Dashboard                  |
| Public content (`/api/v1/changelogs`, `/api/v1/blogs`, etc.) | None required     | Publicly accessible                      |

## API Key Authentication

API keys are used for programmatic access to the Shipstar API. Include your key in the `Authorization` header:

```bash theme={null}
Authorization: Bearer YOUR_API_KEY
```

### Creating API Keys

<Steps>
  <Step title="Sign In">
    Go to [app.shipstar.ai](https://app.shipstar.ai) and sign in to your account.
  </Step>

  <Step title="Navigate to API Keys">
    Click on **API Keys** in the sidebar.
  </Step>

  <Step title="Create New Key">
    Click **Create API Key** and enter a descriptive name.

    <Tip>
      Use descriptive names like "Production Server", "Development", or "CI/CD Pipeline" to easily identify keys later.
    </Tip>
  </Step>

  <Step title="Copy and Store Securely">
    Copy your API key immediately and store it securely. You won't be able to view the full key again — only the first 8 characters are stored for identification.

    <Warning>
      Never share your API key or commit it to version control.
    </Warning>
  </Step>
</Steps>

### API Key Details

* Keys are hashed with SHA-256 before storage — Shipstar never stores your raw key
* Each key tracks a `last_used_at` timestamp
* Keys can have an optional expiration date
* Keys can be deactivated without deletion

## JWT Session Authentication

The internal API (dashboard endpoints) uses JWT tokens obtained by logging in:

```bash theme={null}
# Login to get a JWT token
curl -X POST "https://app.shipstar.ai/api/internal/auth/jwt/login" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "username=you@example.com&password=your_password"
```

```json Response theme={null}
{
  "access_token": "eyJhbGciOiJIUzI1...",
  "token_type": "bearer"
}
```

Use the JWT token the same way as an API key:

```bash theme={null}
Authorization: Bearer eyJhbGciOiJIUzI1...
```

### Token Refresh

JWT tokens expire after a configurable period. Refresh an expired token (within a 30-day grace period) at:

```bash theme={null}
curl -X POST "https://app.shipstar.ai/api/internal/auth/jwt/refresh" \
  -H "Authorization: Bearer YOUR_EXPIRED_TOKEN"
```

## Implementation Examples

### Environment Variables

Always store your API key in environment variables:

<CodeGroup>
  ```bash .env theme={null}
  SHIPSTAR_API_KEY=your_api_key_here
  ```

  ```javascript Node.js theme={null}
  const API_KEY = process.env.SHIPSTAR_API_KEY;

  const response = await fetch('https://app.shipstar.ai/api/v1/me', {
    headers: {
      'Authorization': `Bearer ${API_KEY}`
    }
  });
  ```

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

  API_KEY = os.environ.get('SHIPSTAR_API_KEY')

  response = requests.get(
      'https://app.shipstar.ai/api/v1/me',
      headers={'Authorization': f'Bearer {API_KEY}'}
  )
  ```
</CodeGroup>

### Backend Proxy Pattern

For web applications, create a backend proxy to keep your API key secure:

<CodeGroup>
  ```javascript Next.js API Route theme={null}
  // app/api/generate/route.ts
  export async function POST(req) {
    const { contentType, startDate, endDate } = await req.json();

    const response = await fetch(
      `https://app.shipstar.ai/api/internal/sources/github/${contentType}`,
      {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${process.env.SHIPSTAR_API_KEY}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ start_date: startDate, end_date: endDate })
      }
    );

    const data = await response.json();
    return Response.json(data, { status: response.status });
  }
  ```

  ```javascript Frontend theme={null}
  // Call your backend proxy, not the Shipstar API directly
  const response = await fetch('/api/generate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ contentType: 'changelog' })
  });
  ```
</CodeGroup>

### Reusable Client

Create a reusable client for your application:

```typescript theme={null}
// lib/shipstar-client.ts
class ShipstarClient {
  private apiKey: string;
  private baseUrl = 'https://app.shipstar.ai';

  constructor(apiKey: string) {
    this.apiKey = apiKey;
  }

  private async request(endpoint: string, options: RequestInit = {}) {
    const response = await fetch(`${this.baseUrl}${endpoint}`, {
      ...options,
      headers: {
        'Authorization': `Bearer ${this.apiKey}`,
        'Content-Type': 'application/json',
        ...options.headers
      }
    });

    if (!response.ok) {
      const error = await response.json();
      throw new Error(`API Error ${response.status}: ${error.detail}`);
    }

    return response.json();
  }

  async me() {
    return this.request('/api/v1/me');
  }

  async generateChangelog(startDate?: string, endDate?: string) {
    return this.request('/api/internal/sources/github/changelog', {
      method: 'POST',
      body: JSON.stringify({ start_date: startDate, end_date: endDate })
    });
  }

  async getContent(contentId: string) {
    return this.request(`/api/internal/sources/content/${contentId}`);
  }

  async publishContent(contentId: string) {
    return this.request(`/api/internal/content/${contentId}/publish`, {
      method: 'POST'
    });
  }
}

// Usage
const shipstar = new ShipstarClient(process.env.SHIPSTAR_API_KEY!);
const { content_id } = await shipstar.generateChangelog();
```

## Security Best Practices

<AccordionGroup>
  <Accordion title="Never expose keys in client-side code">
    API keys should never be included in frontend JavaScript, mobile apps, or anywhere they can be viewed by end users.

    ```javascript theme={null}
    // ❌ NEVER do this in frontend code
    const response = await fetch('https://app.shipstar.ai/api/v1/me', {
      headers: { 'Authorization': 'Bearer sk_abc123' }
    });

    // ✅ Call your backend instead
    const response = await fetch('/api/me');
    ```
  </Accordion>

  <Accordion title="Use environment variables">
    Store API keys in environment variables, never in code:

    * Use `.env` files for local development
    * Use secret management services in production (AWS Secrets Manager, HashiCorp Vault, etc.)
    * Never commit `.env` files to version control
  </Accordion>

  <Accordion title="Rotate keys regularly">
    Establish a key rotation schedule:

    1. Create a new API key
    2. Update your application to use the new key
    3. Verify the new key works in production
    4. Deactivate the old key
  </Accordion>

  <Accordion title="Use separate keys for environments">
    Create different API keys for development, staging, and production. This limits the impact if a key is compromised and makes auditing easier.
  </Accordion>

  <Accordion title="Monitor key usage">
    Regularly review your API usage in the Dashboard to detect unusual activity patterns and identify compromised keys.
  </Accordion>
</AccordionGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="401 Unauthorized">
    ```json theme={null}
    { "detail": "Invalid or expired API token." }
    ```

    **Possible causes:**

    * API key is missing from the request
    * API key has been deactivated or expired
    * Using a JWT token that has expired (refresh it)

    **Solutions:**

    * Verify the `Authorization` header is present with the `Bearer ` prefix
    * Check that the key hasn't been deactivated in the Dashboard
    * Create a new API key if needed
  </Accordion>

  <Accordion title="403 Forbidden">
    ```json theme={null}
    { "detail": "Not authorized" }
    ```

    **Possible causes:**

    * Accessing a resource that belongs to another project or team
    * Account restrictions

    **Solutions:**

    * Check that your API key belongs to the correct project
    * Verify your account permissions in the Dashboard
  </Accordion>
</AccordionGroup>

### Testing Your API Key

Use this request to verify your API key is working:

```bash theme={null}
curl -X GET "https://app.shipstar.ai/api/v1/me" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

A successful response confirms your key is valid:

```json theme={null}
{
  "id": "uuid",
  "email": "you@example.com",
  "first_name": "Jane",
  "last_name": "Doe",
  "is_active": true,
  "is_verified": true
}
```
