mirror of
https://github.com/KohakuBlueleaf/KohakuHub.git
synced 2026-07-15 18:25:09 -05:00
521 lines
9.9 KiB
Markdown
521 lines
9.9 KiB
Markdown
---
|
|
title: Authentication API
|
|
description: User registration, login, tokens, email verification, sessions
|
|
icon: 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:**
|
|
```json
|
|
{
|
|
"username": "alice",
|
|
"email": "alice@example.com",
|
|
"password": "secure_password_123"
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "User created successfully",
|
|
"email_verified": true
|
|
}
|
|
```
|
|
|
|
**With Email Verification Enabled:**
|
|
```json
|
|
{
|
|
"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:**
|
|
```json
|
|
{
|
|
"username": "alice",
|
|
"password": "secure_password_123"
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"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:**
|
|
```json
|
|
{
|
|
"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:**
|
|
```json
|
|
{
|
|
"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:**
|
|
```json
|
|
{
|
|
"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:**
|
|
```json
|
|
{
|
|
"name": "My API Token"
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"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:**
|
|
```json
|
|
{
|
|
"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:**
|
|
```json
|
|
{
|
|
"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
|
|
|
|
```python
|
|
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
|
|
|
|
```python
|
|
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
|
|
|
|
```python
|
|
# 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
|
|
|
|
```python
|
|
# 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
|
|
|
|
```bash
|
|
# 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:**
|
|
```json
|
|
{
|
|
"detail": "Invalid username or password"
|
|
}
|
|
```
|
|
|
|
**403 Forbidden:**
|
|
```json
|
|
{
|
|
"detail": "Account is disabled"
|
|
}
|
|
```
|
|
|
|
**400 Bad Request:**
|
|
```json
|
|
{
|
|
"detail": "Username already exists"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Next Steps
|
|
|
|
- [User Settings API](./settings.md) - Profile, preferences
|
|
- [Organizations API](./organizations.md) - Org membership
|
|
- [Invitations API](./invitations.md) - Invite users
|
|
- [Admin API](./admin.md) - User management
|