Overview
FastSkill HTTP API uses JWT (JSON Web Tokens) for authentication and role-based access control (RBAC). Authentication is required for most operations, with different roles having different permission levels.
JWT tokens are generated by the /auth/token endpoint and must be included in the Authorization header as Bearer <token>.
Authentication Flow
1. Get Token
Authenticate with the registry to receive a JWT token.
Endpoint : POST /auth/token
Request Body :
{
"role" : "manager" ,
"username" : "optional-username"
}
Fields :
Field Type Required Description rolestring Yes User role (user, manager, or admin) usernamestring No Optional username for tracking purposes
Example :
# Generate token as manager
curl -X POST http://localhost:8080/auth/token \
-H "Content-Type: application/json" \
-d '{
"role": "manager",
"username": "dev-user"
}'
# Generate token as admin
curl -X POST http://localhost:8080/auth/token \
-H "Content-Type: application/json" \
-d '{
"role": "admin"
}'
Response :
{
"success" : true ,
"data" : {
"token" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhY21lL2FsaWNlIiwicm9sZSI6Im1hbmFnZXIiLCJleHAiOjE3MDk4MzAwMDAsImlhdCI6MTcwNzI0MjQwMH0.signature" ,
"expires_at" : "2025-02-15T10:30:00Z" ,
"role" : "manager"
}
}
2. Use Token
Include the JWT token in the Authorization header for all subsequent requests.
# Use token in request
curl -X GET http://localhost:8080/api/skills \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
# Set token as environment variable for convenience
export TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
curl -X GET http://localhost:8080/api/skills \
-H "Authorization: Bearer $TOKEN "
3. Verify Token (Optional)
Verify that a token is valid and retrieve user information.
Endpoint : GET /auth/verify
Headers :
Authorization: Bearer <token>
Example :
curl -X GET http://localhost:8080/auth/verify \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
Response (valid token):
{
"success" : true ,
"data" : {
"valid" : true ,
"user" : "acme/alice" ,
"role" : "manager" ,
"scope" : "acme" ,
"expires_at" : "2025-02-15T10:30:00Z"
}
}
Response (invalid token):
{
"success" : false ,
"error" : {
"code" : "INVALID_TOKEN" ,
"message" : "Invalid or expired token"
}
}
Role-Based Access Control (RBAC)
FastSkill implements a three-tier role hierarchy:
Role Hierarchy
admin : Full access to all operations including user management and registry configuration
manager : Can publish, update, and delete skills; view registry metrics
user : Read-only access to skills and search functionality
Permission Matrix
Operation user manager admin Read Operations List skills ✓ ✓ ✓ Get skill details ✓ ✓ ✓ Search skills ✓ ✓ ✓ Get skill versions ✓ ✓ ✓ Write Operations Create skills ✗ ✓ ✓ Update skills ✗ ✓ ✓ Delete skills ✗ ✓ ✓ Create skill versions ✗ ✓ ✓ Delete skill versions ✗ ✓ ✓ Enable/disable skills ✗ ✓ ✓ Registry Operations Publish to registry ✗ ✓ ✓ Update manifest ✗ ✓ ✓ View registry metrics ✗ ✓ ✓ Admin Operations Manage users ✗ ✗ ✓ Configure registry ✗ ✗ ✓ View all registry data ✗ ✗ ✓
Scope-Based Authorization
When a user authenticates, their token includes a scope claim that determines which skills they can publish:
{
"sub" : "acme/alice" ,
"scope" : "acme" ,
"role" : "manager"
}
Scope Examples :
User (sub) Scope Can Publish To acme/aliceacmeacme/* skillspersonalpersonalpersonal/* skillscompany/dev-team/bobcompanycompany/* skills
Publishing with Scopes :
When publishing skills, the server automatically prepends the scope to the skill ID:
# User: acme/alice (scope: acme)
# Publish skill with name: web-scraper
# Result: skill published as "acme/web-scraper"
API Key Authentication
For service-to-service integration, FastSkill supports API key authentication.
Header : x-api-key: <api-key>
curl -X GET http://localhost:8080/api/skills \
-H "x-api-key: your-api-key-here"
API keys are typically generated through the registry admin interface or configuration. API keys may have different permissions than JWT tokens.
API Key vs JWT Token
Feature API Key JWT Token Authentication Header x-api-key Header Authorization: Bearer Expiration Never expires (unless revoked) Typically expires in 24 hours User Context No user context Includes user, role, and scope Revocation Can be revoked in admin panel Can be revoked by logout Use Case Service accounts, CI/CD User sessions, interactive use
Token Management
Token Expiration
JWT tokens have a configurable expiration time (default: 24 hours). After expiration:
# Token expired response
{
"success" : false ,
"error" : {
"code" : "INVALID_TOKEN",
"message" : "Token has expired"
}
}
Solution : Generate a new token:
curl -X POST http://localhost:8080/auth/token \
-H "Content-Type: application/json" \
-d '{"role": "manager"}'
Token Refresh
FastSkill CLI automatically manages token refresh when needed:
# CLI automatically checks token expiration
fastskill auth whoami
# If expired, re-authenticate
fastskill auth login --role manager
Token Storage
Tokens are stored locally for reuse:
CLI : Stored in ~/.fastskill/auth.toml
HTTP Clients : Store in application configuration or environment variables
Example storage format :
[[ registries ]]
registry_url = "https://registry.example.com"
username = "dev-user"
role = "manager"
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
expires_at = "2025-02-15T10:30:00Z"
last_refresh = "2025-01-15T10:30:00Z"
Never commit auth.toml or tokens to version control. Rotate tokens regularly for security.
Using Authentication in Different Scenarios
Interactive CLI
# Login once
fastskill auth login --role manager
# Token stored automatically
# All subsequent commands use the token
fastskill list
fastskill search "query"
fastskill publish --artifacts ./artifacts/pptx-1.2.3.zip
Shell Scripts
#!/bin/bash
# 1. Get token
TOKEN = $( curl -s -X POST http://localhost:8080/auth/token \
-H "Content-Type: application/json" \
-d '{"role": "manager"}' | jq -r '.data.token' )
# 2. Use token in requests
curl -X GET http://localhost:8080/api/skills \
-H "Authorization: Bearer $TOKEN "
# 3. Create skill
curl -X POST http://localhost:8080/api/code/v1/skills \
-H "Authorization: Bearer $TOKEN " \
-H "Content-Type: application/json" \
-d '{
"id": "my-skill",
"name": "My Skill",
"description": "Description",
"version": "1.0.0"
}'
Web Applications (JavaScript)
// Fetch token
const response = await fetch ( 'http://localhost:8080/auth/token' , {
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
},
body: JSON . stringify ({
role: 'manager' ,
username: 'web-user'
})
});
const { data } = await response . json ();
const token = data . token ;
// Store token (e.g., localStorage)
localStorage . setItem ( 'fastskill_token' , token );
// Use token in requests
const skillsResponse = await fetch ( 'http://localhost:8080/api/skills' , {
headers: {
'Authorization' : `Bearer ${ token } `
}
});
Python Requests
import requests
# Get token
response = requests.post(
'http://localhost:8080/auth/token' ,
json = { 'role' : 'manager' , 'username' : 'python-user' }
)
data = response.json()
token = data[ 'data' ][ 'token' ]
# Use token in requests
headers = { 'Authorization' : f 'Bearer { token } ' }
skills_response = requests.get(
'http://localhost:8080/api/skills' ,
headers = headers
)
skills = skills_response.json()
Error Handling
Common Authentication Errors
401 Unauthorized
{
"success" : false ,
"error" : {
"code" : "UNAUTHORIZED" ,
"message" : "Missing or invalid authentication token"
}
}
Causes :
No Authorization header provided
Invalid token format
Expired token
Solutions :
Check Authorization header format
Generate a new token
Verify token isn’t truncated
403 Forbidden
{
"success" : false ,
"error" : {
"code" : "FORBIDDEN" ,
"message" : "Insufficient permissions for this operation"
}
}
Causes :
User role insufficient for operation
User doesn’t have access to requested scope
Solutions :
Authenticate with higher role (manager or admin)
Verify scope matches target skill
Contact registry administrator
409 Conflict (Scope Issues)
{
"success" : false ,
"error" : {
"code" : "CONFLICT" ,
"message" : "Skill ID already exists in this scope"
}
}
Causes :
Attempting to publish skill that already exists in scope
Another user in same scope has same skill name
Solutions :
Choose a different skill name
Coordinate with team members
Update existing skill instead of creating new one
Security Best Practices
Use HTTPS
Always use HTTPS for authentication and API requests: # Good
curl https://registry.example.com/auth/token
# Bad - insecure
curl http://registry.example.com/auth/token
Protect Tokens
Never expose tokens in:
URL parameters
Client-side JavaScript (except in secure sessionStorage)
Version control
Logs or error messages
Public documentation
Rotate Tokens
Regularly rotate JWT tokens:
Logout and re-authenticate periodically
Use short expiration times for high-risk environments
Revoke compromised tokens immediately
Use Appropriate Roles
Assign minimal required role:
Use user for read-only applications
Use manager for publishing workflows
Use admin only for administration
Store Tokens Securely
Use secure storage mechanisms (keychain, secret managers)
Restrict file permissions on token storage files
Never hardcode tokens in source code
Use environment variables for CI/CD
CI/CD Integration
GitHub Actions
name : Publish Skill
on :
push :
branches : [ main ]
jobs :
publish :
runs-on : ubuntu-latest
steps :
- uses : actions/checkout@v3
- name : Authenticate
id : auth
run : |
TOKEN=$(curl -s -X POST ${{ secrets.REGISTRY_URL }}/auth/token \
-H "Content-Type: application/json" \
-d '{"role": "manager"}' | jq -r '.data.token')
echo "token=$TOKEN" >> $GITHUB_OUTPUT
env :
REGISTRY_URL : ${{ secrets.REGISTRY_URL }}
- name : Publish skill
run : |
curl -X POST ${{ secrets.REGISTRY_URL }}/api/code/v1/skills \
-H "Authorization: Bearer ${{ steps.auth.outputs.token }}" \
-H "Content-Type: application/json" \
-d @skill.json
GitLab CI
publish :
script :
- |
# Get token
TOKEN=$(curl -s -X POST $REGISTRY_URL/auth/token \
-H "Content-Type: application/json" \
-d '{"role": "manager"}' | jq -r '.data.token')
# Publish skill
curl -X POST $REGISTRY_URL/api/code/v1/skills \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d @skill.json
variables :
REGISTRY_URL : https://registry.example.com
Troubleshooting
Token expired immediately
Verify header format : Ensure Authorization: Bearer <token> format (with space after “Bearer”).# Correct
curl -H "Authorization: Bearer $TOKEN "
# Incorrect (missing space)
curl -H "Authorization:Bearer $TOKEN "
Check role : Verify your role has permissions for the operation.# Verify your role
curl -H "Authorization: Bearer $TOKEN " \
http://localhost:8080/auth/verify
# Re-authenticate with higher role if needed
fastskill auth login --role admin
See Also