REST API Reference
The Voidkey broker exposes a RESTful API for credential minting and management.
Base URL
Section titled “Base URL”https://voidkey.example.comAuthentication
Section titled “Authentication”All API requests require a valid OIDC token from a configured client IdP:
curl -X POST https://voidkey.example.com/credentials/mint \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \ -H "Content-Type: application/json" \ -d '{"keys": ["AWS_DEPLOY"]}'Common Headers
Section titled “Common Headers”| Header | Required | Description |
|---|---|---|
Authorization | Yes* | Bearer token with OIDC token |
Content-Type | Yes** | application/json for POST/PUT |
X-Request-ID | No | Correlation ID for request tracking |
* Not required for health endpoint
** Only for requests with body
API Endpoints
Section titled “API Endpoints”POST /credentials/mint
Section titled “POST /credentials/mint”Mint temporary credentials for specified keys.
Request
Section titled “Request”POST /credentials/mint HTTP/1.1Host: voidkey.example.comAuthorization: Bearer eyJhbGciOiJSUzI1NiIs...Content-Type: application/json
{ "oidcToken": "eyJhbGciOiJSUzI1NiIs...", "keys": ["AWS_DEPLOY", "GCP_READONLY"]}Request Body
Section titled “Request Body”| Field | Type | Required | Description |
|---|---|---|---|
oidcToken | string | No* | OIDC token (if not in Authorization header) |
keys | string[] | Yes | Array of key names to mint |
* Token must be provided either in Authorization header or request body
Response
Section titled “Response”HTTP/1.1 200 OKContent-Type: application/jsonX-Request-ID: 550e8400-e29b-41d4-a716-446655440000
{ "credentials": { "AWS_DEPLOY": { "AWS_ACCESS_KEY_ID": "ASIATESTACCESSKEY", "AWS_SECRET_ACCESS_KEY": "wJalrXUtnFEMI/K7MDENG/bPxRfiCY", "AWS_SESSION_TOKEN": "FwoGZXIvYXdzEBYaD...", "AWS_REGION": "us-east-1" }, "GCP_READONLY": { "GOOGLE_OAUTH_ACCESS_TOKEN": "ya29.A0ARrdaM...", "GOOGLE_TOKEN_EXPIRY": "2024-01-15T12:00:00Z" } }, "expiresAt": "2024-01-15T11:00:00Z", "subject": "repo:myorg/myapp:ref:refs/heads/main", "issuedAt": "2024-01-15T10:00:00Z"}Response Fields
Section titled “Response Fields”| Field | Type | Description |
|---|---|---|
credentials | object | Map of key names to credential values |
expiresAt | string | ISO 8601 timestamp when credentials expire |
subject | string | Subject claim from OIDC token |
issuedAt | string | ISO 8601 timestamp when credentials were issued |
Error Responses
Section titled “Error Responses”400 Bad Request
{ "error": "INVALID_REQUEST", "message": "Missing required field: keys", "details": { "field": "keys", "reason": "required" }}401 Unauthorized
{ "error": "UNAUTHORIZED", "message": "Invalid or expired token"}403 Forbidden
{ "error": "FORBIDDEN", "message": "Subject 'user:alice@example.com' does not have access to key 'AWS_PROD'"}404 Not Found
{ "error": "NOT_FOUND", "message": "Key 'INVALID_KEY' not found for subject"}500 Internal Server Error
{ "error": "INTERNAL_ERROR", "message": "Failed to mint credentials", "requestId": "550e8400-e29b-41d4-a716-446655440000"}GET /credentials/keys
Section titled “GET /credentials/keys”List available keys for the authenticated subject.
Request
Section titled “Request”GET /credentials/keys?token=eyJhbGciOiJSUzI1NiIs... HTTP/1.1Host: voidkey.example.comOr with Authorization header:
GET /credentials/keys HTTP/1.1Host: voidkey.example.comAuthorization: Bearer eyJhbGciOiJSUzI1NiIs...Query Parameters
Section titled “Query Parameters”| Parameter | Type | Required | Description |
|---|---|---|---|
token | string | No* | OIDC token (if not in Authorization header) |
Response
Section titled “Response”HTTP/1.1 200 OKContent-Type: application/json
{ "subject": "repo:myorg/myapp:ref:refs/heads/main", "idp": "github-actions", "keys": [ { "name": "AWS_DEPLOY", "provider": "aws-prod", "description": "AWS deployment credentials", "maxDuration": 3600 }, { "name": "GCP_READONLY", "provider": "gcp-prod", "description": "GCP read-only access", "maxDuration": 7200 } ]}GET /credentials/idp-providers
Section titled “GET /credentials/idp-providers”List configured identity providers.
Request
Section titled “Request”GET /credentials/idp-providers HTTP/1.1Host: voidkey.example.comResponse
Section titled “Response”HTTP/1.1 200 OKContent-Type: application/json
{ "providers": [ { "name": "github-actions", "issuer": "https://token.actions.githubusercontent.com", "type": "oidc" }, { "name": "auth0-dev", "issuer": "https://dev.auth0.com/", "type": "oidc" }, { "name": "keycloak", "issuer": "https://auth.example.com/realms/developers", "type": "oidc" } ]}GET /health
Section titled “GET /health”Health check endpoint for monitoring and load balancers.
Request
Section titled “Request”GET /health HTTP/1.1Host: voidkey.example.comResponse
Section titled “Response”Healthy
HTTP/1.1 200 OKContent-Type: application/json
{ "status": "healthy", "timestamp": "2024-01-15T10:30:00Z", "version": "0.8.0", "uptime": 3600, "checks": { "broker_idp": "healthy", "config": "healthy", "memory": "healthy" }}Unhealthy
HTTP/1.1 503 Service UnavailableContent-Type: application/json
{ "status": "unhealthy", "timestamp": "2024-01-15T10:30:00Z", "version": "0.8.0", "uptime": 3600, "checks": { "broker_idp": "unhealthy", "config": "healthy", "memory": "healthy" }, "errors": [ "Cannot connect to broker IdP" ]}Rate Limiting
Section titled “Rate Limiting”The API implements rate limiting to prevent abuse:
- Default limit: 100 requests per minute per IP
- Burst limit: 20 requests
- Headers returned:
X-RateLimit-Limit: Maximum requests per windowX-RateLimit-Remaining: Requests remainingX-RateLimit-Reset: Unix timestamp when limit resets
Rate limit exceeded response:
HTTP/1.1 429 Too Many RequestsContent-Type: application/jsonX-RateLimit-Limit: 100X-RateLimit-Remaining: 0X-RateLimit-Reset: 1705316400
{ "error": "RATE_LIMIT_EXCEEDED", "message": "Too many requests. Please retry after 1705316400", "retryAfter": 60}CORS Configuration
Section titled “CORS Configuration”The API supports CORS for browser-based clients:
OPTIONS /credentials/mint HTTP/1.1Host: voidkey.example.comOrigin: https://app.example.comAccess-Control-Request-Method: POSTAccess-Control-Request-Headers: authorization,content-type
HTTP/1.1 204 No ContentAccess-Control-Allow-Origin: https://app.example.comAccess-Control-Allow-Methods: GET, POST, OPTIONSAccess-Control-Allow-Headers: authorization, content-typeAccess-Control-Max-Age: 86400Error Response Format
Section titled “Error Response Format”All error responses follow a consistent format:
interface ErrorResponse { error: string; // Error code (SCREAMING_SNAKE_CASE) message: string; // Human-readable message details?: any; // Additional error details requestId?: string; // Request correlation ID retryAfter?: number; // Seconds to wait before retry}Common Error Codes
Section titled “Common Error Codes”| Code | HTTP Status | Description |
|---|---|---|
INVALID_REQUEST | 400 | Malformed request or missing required fields |
INVALID_TOKEN | 401 | Token validation failed |
UNAUTHORIZED | 401 | Missing or invalid authentication |
FORBIDDEN | 403 | Authenticated but not authorized |
NOT_FOUND | 404 | Requested resource not found |
RATE_LIMIT_EXCEEDED | 429 | Too many requests |
INTERNAL_ERROR | 500 | Server-side error |
SERVICE_UNAVAILABLE | 503 | Service temporarily unavailable |
SDK Examples
Section titled “SDK Examples”JavaScript/TypeScript
Section titled “JavaScript/TypeScript”import axios from 'axios';
class VoidkeyClient { constructor(private baseUrl: string) {}
async mintCredentials(token: string, keys: string[]) { const response = await axios.post( `${this.baseUrl}/credentials/mint`, { keys }, { headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json', }, } ); return response.data; }
async listKeys(token: string) { const response = await axios.get( `${this.baseUrl}/credentials/keys`, { headers: { 'Authorization': `Bearer ${token}`, }, } ); return response.data; }}
// Usageconst client = new VoidkeyClient('https://voidkey.example.com');const creds = await client.mintCredentials(oidcToken, ['AWS_DEPLOY']);Python
Section titled “Python”import requestsfrom typing import List, Dict
class VoidkeyClient: def __init__(self, base_url: str): self.base_url = base_url self.session = requests.Session()
def mint_credentials(self, token: str, keys: List[str]) -> Dict: response = self.session.post( f"{self.base_url}/credentials/mint", json={"keys": keys}, headers={ "Authorization": f"Bearer {token}", "Content-Type": "application/json", } ) response.raise_for_status() return response.json()
def list_keys(self, token: str) -> Dict: response = self.session.get( f"{self.base_url}/credentials/keys", headers={"Authorization": f"Bearer {token}"} ) response.raise_for_status() return response.json()
# Usageclient = VoidkeyClient("https://voidkey.example.com")creds = client.mint_credentials(oidc_token, ["AWS_DEPLOY"])package voidkey
import ( "bytes" "encoding/json" "fmt" "net/http")
type Client struct { BaseURL string HTTP *http.Client}
type MintRequest struct { Keys []string `json:"keys"`}
type MintResponse struct { Credentials map[string]map[string]string `json:"credentials"` ExpiresAt string `json:"expiresAt"` Subject string `json:"subject"`}
func (c *Client) MintCredentials(token string, keys []string) (*MintResponse, error) { body, _ := json.Marshal(MintRequest{Keys: keys})
req, err := http.NewRequest("POST", c.BaseURL+"/credentials/mint", bytes.NewReader(body)) if err != nil { return nil, err }
req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json")
resp, err := c.HTTP.Do(req) if err != nil { return nil, err } defer resp.Body.Close()
if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("unexpected status: %d", resp.StatusCode) }
var result MintResponse if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return nil, err }
return &result, nil}Best Practices
Section titled “Best Practices”-
Token Handling
- Always use HTTPS
- Prefer Authorization header over query parameters
- Never log tokens
-
Error Handling
- Implement exponential backoff for retries
- Handle rate limits gracefully
- Log request IDs for debugging
-
Performance
- Reuse HTTP connections
- Request only needed keys
- Cache responses appropriately
-
Security
- Validate certificates
- Implement request timeouts
- Sanitize error messages
Next Steps
Section titled “Next Steps”- API Endpoints - Detailed endpoint documentation
- Authentication - Authentication methods
- CLI Reference - Using the CLI client
- Examples - Integration examples