Skip to content

Authentication

v7.3 adds scoped API key authentication for the index server, enabling secure multi-tenant access with fine-grained permissions.

Scopes

Scope Permissions
read GET requests, symbol lookup, search
write POST requests, upload indexes, create repos
admin Full access including token management and deletions

Scopes are hierarchical: admin includes write, which includes read.

Token Management CLI

# Create a new token
ckb token create --name "CI Upload" --scopes write
ckb token create --name "Read-only" --scopes read --repos "myorg/*"
ckb token create --name "Admin" --scopes admin --expires 30d

# List all tokens
ckb token list
ckb token list --show-revoked

# Revoke a token
ckb token revoke ckb_key_abc123

# Rotate a token (new secret, same ID)
ckb token rotate ckb_key_abc123

Token Format

  • Token: ckb_sk_ prefix + 64 hex chars (shown once at creation)
  • Key ID: ckb_key_ prefix + 16 hex chars (used for management)

Tokens are bcrypt hashed before storage — only the prefix is visible in token list.

Configuration

[index_server.auth]
enabled = true
require_auth = true                    # false = unauthenticated gets read-only
legacy_token = "${CKB_LEGACY_TOKEN}"   # Backward compatibility

# Static keys (defined in config, useful for CI)
[index_server.auth.static_keys](/docs/index_server.auth.static_keys)
id = "ci-upload"
name = "CI Upload Key"
token = "${CI_CKB_TOKEN}"              # Supports env var expansion
scopes = ["write"]
repo_patterns = ["myorg/*"]            # Restrict to matching repos
rate_limit = 100

[index_server.auth.rate_limiting]
enabled = true
default_limit = 60                     # Requests per minute
burst_size = 10

Per-Repo Restrictions

Keys can be restricted to specific repositories using glob patterns:

# Create a key that only works for myorg/* repos
ckb token create --name "MyOrg CI" --scopes write --repos "myorg/*"

Pattern syntax:

  • * — Match all repos
  • myorg/* — Match all repos starting with myorg/
  • myorg/api — Match exact repo ID

Rate Limiting

When enabled, rate limiting uses a token bucket algorithm:

[index_server.auth.rate_limiting]
enabled = true
default_limit = 60    # Tokens per minute
burst_size = 10       # Initial bucket size

When rate limited, the server responds with:

  • 429 Too Many Requests
  • Retry-After: <seconds> header
  • X-RateLimit-Remaining: 0 header

HTTP Authentication

Use the Authorization header with Bearer token:

# Read operations (GET)
curl -H "Authorization: Bearer ckb_sk_..." http://localhost:8080/index/repos

# Write operations (POST) - requires write scope
curl -X POST -H "Authorization: Bearer ckb_sk_..." \
  -H "Content-Type: application/octet-stream" \
  --data-binary @index.scip \
  http://localhost:8080/index/repos/myorg/myrepo/upload

# Delete operations - requires admin scope
curl -X DELETE -H "Authorization: Bearer ckb_sk_..." \
  http://localhost:8080/index/repos/myorg/myrepo

Error Responses

Status Error Code Meaning
401 missing_token No Authorization header
401 invalid_token Token not found or malformed
401 expired_token Token past expiration
401 revoked_token Token was revoked
403 insufficient_scope Token lacks required scope
403 repo_not_allowed Token restricted to other repos
429 rate_limited Too many requests (check Retry-After header)

Error response format:

{
  "error": {
    "code": "insufficient_scope",
    "message": "token requires 'write' scope for this operation"
  }
}

Backward Compatibility

Legacy Token Mode: If you were using the simple token config before, you can migrate by setting legacy_token:

[index_server.auth]
enabled = true
legacy_token = "${OLD_TOKEN}"   # Old token still works

The legacy token has full admin access.

Unauthenticated Access: When require_auth = false, unauthenticated requests get read-only access. This is useful for public indexes where you want anyone to query but restrict uploads.

Use Cases

CI/CD Index Publishing

# Create a write-only token for CI
ckb token create --name "CI" --scopes write --repos "myorg/*"

# In CI pipeline
curl -X POST http://codeserver.internal/index/repos/$REPO_ID/upload \
  -H "Authorization: Bearer $CKB_CI_TOKEN" \
  -H "X-CKB-Commit: $GIT_SHA" \
  --data-binary @index.scip

See CI-CD-Integration for full pipeline examples.

Multi-Tenant Server

# Create restricted keys for each team
ckb token create --name "Team A" --scopes write --repos "team-a/*"
ckb token create --name "Team B" --scopes write --repos "team-b/*"

Read-Only API Access

# Token for querying only
ckb token create --name "Dashboard" --scopes read --rate-limit 120

Air-Gapped Environments

Generate SCIP indexes in restricted environments and upload to a central server via HTTP.

Daemon Mode Authentication

The daemon has its own simpler authentication for local API access:

{
  "auth": {
    "enabled": true,
    "token": "${CKB_DAEMON_TOKEN}"
  }
}

When enabled, all daemon API requests require the bearer token:

curl -H "Authorization: Bearer $CKB_DAEMON_TOKEN" http://localhost:9120/daemon/status

See Daemon-Mode for full daemon configuration.