---
title: "Why Linkbreakers Uses accessToken Instead of apiKey"
description: "Learn why the Linkbreakers SDK requires accessToken (not apiKey) for authentication, how JWT tokens work, and how to fix common authentication errors in TypeScript, Python, and raw HTTP requests."
canonical: "https://linkbreakers.com/help/article/api-authentication-accesstoken-vs-apikey"
last-updated: 2025-03-20
---

# Why Linkbreakers Uses accessToken Instead of apiKey

> Learn why the Linkbreakers SDK requires accessToken (not apiKey) for authentication, how JWT tokens work, and how to fix common authentication errors in TypeScript, Python, and raw HTTP requests.

## Short answer

Linkbreakers uses `accessToken` (not `apiKey`) for SDK authentication because all API keys are JWT tokens containing encoded access information, scopes, and permissions. Using `apiKey` won't send proper authentication headers, causing 401 Unauthorized errors.

## The difference: accessToken vs apiKey

When configuring the Linkbreakers SDK, you must use the `accessToken` parameter:

```typescript
// ✅ CORRECT - Sends authentication headers
const config = new Configuration({
  accessToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
  basePath: 'https://api.linkbreakers.com',
});

// ❌ WRONG - Does NOT authenticate
const config = new Configuration({
  apiKey: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',  // This parameter is ignored!
});
```

**Why this matters:** The underlying OpenAPI-generated SDK code uses `accessToken` to populate the `Authorization: Bearer {token}` header. The `apiKey` parameter is designed for a different authentication scheme (API key headers like `X-API-Key`) which Linkbreakers doesn't use.

## Why JWT tokens?

Linkbreakers API keys are **JSON Web Tokens (JWT)**, not simple API keys. This design provides several advantages:

### What's inside the JWT

When you create an API key, Linkbreakers generates a JWT containing:

- **Workspace ID**: Which workspace the key belongs to
- **Key type**: Publishable or secret (determines permissions)
- **Scopes/permissions**: What operations the key can perform
- **Environment**: Whether the key is for test or production data
- **Expiration**: Optional expiration timestamp (iat, exp claims)
- **Issued at**: When the key was created
- **Key metadata**: Additional context about key usage

### Benefits of JWT tokens

**Server-side validation without database lookups:** The API can verify and decode the JWT to extract workspace ID and permissions without querying the database for every request, improving performance.

**Built-in permissions:** The token itself contains scope information (encoded in JWT claims), allowing the API to enforce permission restrictions at the token level without external lookups.

**Revocation tracking:** While JWTs are stateless, Linkbreakers maintains a revocation list for invalidated tokens, providing the best of both worlds.

**Tamper-proof:** JWTs are cryptographically signed, making them impossible to forge or modify without detection.

## TypeScript SDK: Correct usage

```typescript
import { Configuration, LinksApi } from 'linkbreakers';

// ✅ CORRECT
const config = new Configuration({
  accessToken: process.env.LINKBREAKERS_SECRET_KEY,  // Use accessToken
  basePath: 'https://api.linkbreakers.com',
});

const linksApi = new LinksApi(config);

const response = await linksApi.linksServiceCreate({
  createLinkRequest: {
    destination: 'https://example.com',
    name: 'My Link'
  }
});
```

### What happens under the hood

When you use `accessToken`, the SDK sends:

```http
POST /v1/links HTTP/1.1
Host: api.linkbreakers.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3b3Jrc3BhY2VfaWQiOiIxMjM0In0...
Content-Type: application/json

{"destination":"https://example.com","name":"My Link"}
```

## Python SDK: Correct usage

```python
from linkbreakers import Configuration, ApiClient, LinksApi

# ✅ CORRECT
configuration = Configuration(
    access_token=os.getenv('LINKBREAKERS_SECRET_KEY'),  # Use access_token
    host='https://api.linkbreakers.com'
)

with ApiClient(configuration) as api_client:
    links_api = LinksApi(api_client)

    response = links_api.links_service_create({
        'destination': 'https://example.com',
        'name': 'My Link'
    })
```

## Raw HTTP: Using the API directly

If you're not using the SDK and making direct HTTP requests, include the API key in the `Authorization` header with the `Bearer` scheme:

```bash
# ✅ CORRECT - Using Bearer token (JWT)
curl -X POST https://api.linkbreakers.com/v1/links \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json" \
  -d '{
    "destination": "https://example.com",
    "name": "My Link"
  }'
```

```javascript
// ✅ CORRECT - Fetch API with JWT
const response = await fetch('https://api.linkbreakers.com/v1/links', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    destination: 'https://example.com',
    name: 'My Link'
  })
});
```

```python
# ✅ CORRECT - requests library with JWT
import requests

response = requests.post(
    'https://api.linkbreakers.com/v1/links',
    headers={
        'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
        'Content-Type': 'application/json'
    },
    json={
        'destination': 'https://example.com',
        'name': 'My Link'
    }
)
```

### Wrong approaches (don't use these)

```bash
# ❌ WRONG - Custom API key header (not supported)
curl -X POST https://api.linkbreakers.com/v1/links \
  -H "X-API-Key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -d '{"destination":"https://example.com"}'

# ❌ WRONG - Query parameter (not supported)
curl -X POST "https://api.linkbreakers.com/v1/links?api_key=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -d '{"destination":"https://example.com"}'

# ❌ WRONG - Basic auth (not supported)
curl -X POST https://api.linkbreakers.com/v1/links \
  -u "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...:" \
  -d '{"destination":"https://example.com"}'
```

## Common authentication errors

### Error: "401 Unauthorized"

**Cause:** You used `apiKey` instead of `accessToken` in the SDK configuration, or didn't include the `Authorization` header in raw HTTP requests.

**Fix:**

```typescript
// Change this:
const config = new Configuration({
  apiKey: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',  // ❌ Wrong
});

// To this:
const config = new Configuration({
  accessToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',  // ✅ Correct
});
```

### Error: "Missing or invalid authorization header"

**Cause:** The `Authorization` header is missing or doesn't use the `Bearer` scheme.

**Fix:** Ensure the header format is exactly `Authorization: Bearer {your_token}`

### Error: "Invalid token signature"

**Cause:** The JWT token is malformed, expired, or has been tampered with.

**Fix:** Generate a new API key from your dashboard and replace the old one.

## Testing your authentication

Verify your authentication is working correctly:

```bash
# Test with curl
curl -X GET https://api.linkbreakers.com/v1/links \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -w "\nHTTP Status: %{http_code}\n"

# Should return HTTP Status: 200 with your links list
# If you get HTTP Status: 401, check your JWT token and header format
```

## Frequently asked questions

**Why doesn't Linkbreakers use traditional API keys?**

Traditional API keys are just random strings that require database lookups on every request. JWTs encode access information directly in the token, enabling faster authentication and permission checks.

**Can I decode my API key to see what's inside?**

Yes! JWTs are base64-encoded and can be decoded (but not modified without invalidation). You can paste your token into [jwt.io](https://jwt.io) to inspect the payload and see the workspace ID, scopes, and environment. However, never share your tokens publicly.

**What if I accidentally used apiKey instead of accessToken?**

Your requests will fail with 401 Unauthorized errors because no authentication headers are sent. Simply change `apiKey` to `accessToken` in your configuration.

**Does the JWT contain my secret data?**

No. The JWT only contains metadata about the key itself (workspace ID, permissions, key type). It doesn't contain sensitive workspace data.

**Why Bearer authentication instead of X-API-Key headers?**

Bearer tokens are the industry standard for OAuth 2.0 and JWT-based authentication. They're well-supported by HTTP clients, API gateways, and have better tooling support than custom header schemes.

## Sources

- [JSON Web Tokens (JWT) Introduction](https://jwt.io/introduction)
- [RFC 6750: Bearer Token Usage](https://datatracker.ietf.org/doc/html/rfc6750)
- [Linkbreakers TypeScript SDK Quick Start](/help/article/typescript-sdk-quickstart)
- [Linkbreakers Python SDK Quick Start](/help/article/python-sdk-quickstart)

## Last reviewed

This article was last reviewed on March 20, 2025.
