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 reposmyorg/*— Match all repos starting withmyorg/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 RequestsRetry-After: <seconds>headerX-RateLimit-Remaining: 0header
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.
Related Pages
- Configuration — Full configuration reference
- CI-CD-Integration — Pipeline authentication setup
- Daemon-Mode — Daemon authentication
- Federation — Cross-repo access control
- API-Reference — HTTP API endpoints