Files
KohakuHub/docs/api/authentication.md
2025-10-24 18:45:55 +08:00

9.9 KiB

title, description, icon
title description icon
Authentication API User registration, login, tokens, email verification, sessions i-carbon-password

Authentication API

User authentication, registration, API token management, and email verification.


Registration

Register New User

Pattern: POST /auth/register

Authentication: Public (no auth required)

Query Parameters:

  • invitation_token (optional): Required if server is in invitation-only mode

Request Body:

{
  "username": "alice",
  "email": "alice@example.com",
  "password": "secure_password_123"
}

Response:

{
  "success": true,
  "message": "User created successfully",
  "email_verified": true
}

With Email Verification Enabled:

{
  "success": true,
  "message": "User created. Please check your email to verify your account.",
  "email_verified": false
}

Validation:

  • Username: Not reserved, not already taken, no normalized conflicts
  • Email: Valid format, not already registered
  • Password: Minimum length (enforced by server config)

Reserved Usernames: models, datasets, spaces, admin, api, organizations, settings, new, login, register, logout, docs, and more (see validation.py)

Status Codes:

  • 200 OK - User created
  • 400 Bad Request - Username/email taken, reserved name, or validation error
  • 403 Forbidden - Invitation required but not provided

Login & Sessions

Login

Pattern: POST /auth/login

Authentication: Public

Request Body:

{
  "username": "alice",
  "password": "secure_password_123"
}

Response:

{
  "success": true,
  "message": "Logged in successfully",
  "username": "alice",
  "session_secret": "random_secret_for_client_side_encryption"
}

Response Headers:

Set-Cookie: session_id=abc123...; HttpOnly; SameSite=Lax; Max-Age=2592000

Session Duration: 30 days (default, configurable)

Checks:

  • Username and password match
  • Account is active (is_active = true)
  • Email verified (if require_email_verification = true)

Status Codes:

  • 200 OK - Logged in successfully
  • 401 Unauthorized - Invalid credentials
  • 403 Forbidden - Account disabled or email not verified

Logout

Pattern: POST /auth/logout

Authentication: Required (session cookie or token)

Response:

{
  "success": true,
  "message": "Logged out successfully"
}

Behavior:

  • Deletes all user sessions from database
  • Clears session_id cookie

Get Current User

Pattern: GET /auth/me

Authentication: Required

Response:

{
  "id": 1,
  "username": "alice",
  "email": "alice@example.com",
  "email_verified": true,
  "created_at": "2025-01-01T00:00:00Z"
}

Use Case: Check if still logged in, get basic user info


API Tokens

List Tokens

Pattern: GET /auth/tokens

Authentication: Required (session cookie or existing token)

Response:

{
  "tokens": [
    {
      "id": 1,
      "name": "My API Token",
      "last_used": "2025-01-20T10:15:32Z",
      "created_at": "2025-01-01T00:00:00Z"
    },
    {
      "id": 2,
      "name": "CI/CD Token",
      "last_used": null,
      "created_at": "2025-01-15T08:00:00Z"
    }
  ]
}

Notes:

  • Token values are never shown after creation
  • last_used updates when token is used
  • Tokens don't expire by default

Create Token

Pattern: POST /auth/tokens/create

Authentication: Required

Request Body:

{
  "name": "My API Token"
}

Response:

{
  "success": true,
  "token": "hf_abc123def456ghi789jkl...",
  "token_id": 3,
  "session_secret": "encryption_secret",
  "message": "Token created. Save it securely - you won't see it again!"
}

Important:

  • Token value shown only once
  • Copy immediately and store securely
  • Cannot retrieve token value later
  • Prefix: hf_ (HuggingFace compatible)

Revoke Token

Pattern: DELETE /auth/tokens/{token_id}

Authentication: Required (must own token)

Response:

{
  "success": true,
  "message": "Token revoked successfully"
}

Status Codes:

  • 200 OK - Token revoked
  • 404 Not Found - Token not found or not owned by user

Email Verification

Verify Email

Pattern: GET /auth/verify-email?token={verification_token}

Authentication: Public

Purpose: Verify email address after registration

Response:

  • Redirects to user profile on success: 302 -> /{username}
  • Redirects to login with error on failure: 302 -> /?error=invalid_token

Behavior:

  1. Validates verification token
  2. Checks token not expired (24 hours default)
  3. Marks user email as verified
  4. Deletes verification token
  5. Creates session and auto-logs in user

Cookie Set:

Set-Cookie: session_id=abc123...; HttpOnly; SameSite=Lax

Resend Verification Email

Pattern: POST /auth/resend-verification

Authentication: Required (can be unverified user)

Purpose: Resend verification email if not received

Response:

{
  "success": true,
  "message": "Verification email sent"
}

Validation:

  • User must not be already verified
  • Rate limit: Once per hour (TODO: implement)

Usage Examples

Register and Login

import requests

API_BASE = "http://localhost:28080"

# Register
register_resp = requests.post(
    f"{API_BASE}/auth/register",
    json={
        "username": "alice",
        "email": "alice@example.com",
        "password": "secure123"
    }
)

result = register_resp.json()
print(result["message"])

# If email verification required
if not result.get("email_verified"):
    print("Check your email and click verification link")
    # After clicking link, user is auto-logged in

# Login (if email verification not required)
login_resp = requests.post(
    f"{API_BASE}/auth/login",
    json={
        "username": "alice",
        "password": "secure123"
    }
)

# Session cookie set automatically
session_cookie = login_resp.cookies.get("session_id")
print(f"Session ID: {session_cookie}")

Create and Use API Token

import requests

API_BASE = "http://localhost:28080"

# Login first (or use existing session)
session = requests.Session()
session.post(
    f"{API_BASE}/auth/login",
    json={"username": "alice", "password": "secure123"}
)

# Create token
token_resp = session.post(
    f"{API_BASE}/auth/tokens/create",
    json={"name": "My API Token"}
)

token_data = token_resp.json()
token = token_data["token"]  # hf_abc123...

print(f"Token created: {token}")
print("SAVE THIS TOKEN - you won't see it again!")

# Use token in API requests
headers = {"Authorization": f"Bearer {token}"}

# List repositories
repos_resp = requests.get(
    f"{API_BASE}/api/models",
    headers=headers
)

print(f"Found {len(repos_resp.json())} models")

Manage Tokens

# List all tokens
tokens_resp = session.get(f"{API_BASE}/auth/tokens")
tokens = tokens_resp.json()["tokens"]

for t in tokens:
    print(f"Token: {t['name']} (ID: {t['id']})")
    print(f"  Created: {t['created_at']}")
    print(f"  Last used: {t['last_used'] or 'Never'}")

# Revoke old token
old_token_id = tokens[0]["id"]
revoke_resp = session.delete(f"{API_BASE}/auth/tokens/{old_token_id}")
print(revoke_resp.json()["message"])

Registration with Invitation

# For invitation-only servers
invitation_token = "invitation_token_from_link"

register_resp = requests.post(
    f"{API_BASE}/auth/register?invitation_token={invitation_token}",
    json={
        "username": "bob",
        "email": "bob@example.com",
        "password": "secure456"
    }
)

# If invitation was for joining an organization
# User automatically added to that organization

Security

Password Hashing

  • Algorithm: bcrypt
  • Salt rounds: Automatic (bcrypt default)
  • Passwords never stored in plaintext

Session Security

  • HTTP-only cookies (not accessible via JavaScript)
  • SameSite: Lax (CSRF protection)
  • Secure flag in production (HTTPS only)
  • 30-day expiration (configurable)

Token Security

  • SHA256 hashed in database
  • Prefix: hf_ (64 characters total)
  • Never logged in plaintext
  • Single-use viewing (on creation only)

Session Secret

  • Random 32-character string
  • Used for client-side token encryption
  • Unique per session
  • Returned on login and token creation

Configuration

Environment Variables

# Session duration (hours)
KOHAKU_HUB_SESSION_EXPIRE_HOURS=720  # 30 days default

# Email verification
KOHAKU_HUB_REQUIRE_EMAIL_VERIFICATION=false

# Invitation-only registration
KOHAKU_HUB_INVITATION_ONLY=false

# Session secret (for cookie signing)
KOHAKU_HUB_SESSION_SECRET=change_this_in_production

# Email SMTP (for verification emails)
KOHAKU_HUB_SMTP_HOST=smtp.gmail.com
KOHAKU_HUB_SMTP_PORT=587
KOHAKU_HUB_SMTP_USERNAME=your_email@gmail.com
KOHAKU_HUB_SMTP_PASSWORD=your_app_password
KOHAKU_HUB_SMTP_FROM=noreply@yourdomain.com

Best Practices

For Users:

  • Use strong passwords (mix of letters, numbers, symbols)
  • Create tokens for CI/CD (don't use password)
  • Revoke unused tokens
  • Don't share tokens in public repos

For Developers:

  • Store tokens in environment variables
  • Use session cookies for browser apps
  • Use Bearer tokens for API/CLI
  • Handle 401/403 errors (prompt re-login)

For Admins:

  • Enable email verification in production
  • Use invitation-only mode for private instances
  • Set strong SESSION_SECRET
  • Enable HTTPS in production
  • Monitor token usage via admin API

Error Responses

401 Unauthorized:

{
  "detail": "Invalid username or password"
}

403 Forbidden:

{
  "detail": "Account is disabled"
}

400 Bad Request:

{
  "detail": "Username already exists"
}

Next Steps