Authentication
The Vidivo authentication system uses JWT RS256 tokens. Access tokens expire after 15 minutes; refresh tokens expire after 30 days and are rotated on each use.
All auth endpoints are unauthenticated (no Bearer token required).
POST /auth/register
Section titled “POST /auth/register”Create a new user account.
Rate limit: 3 requests per hour per IP.
Request
Section titled “Request”POST /v1/auth/registerContent-Type: application/json{ "email": "jane@example.com", "password": "SecureP@ssw0rd!", "display_name": "Jane Smith"}| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | Valid email address. Must be unique. |
password | string | Yes | Minimum 8 characters. |
display_name | string | No | Public name shown to guests. Max 80 characters. |
Response
Section titled “Response”HTTP/1.1 201 CreatedContent-Type: application/json{ "user": { "id": "01JN2X4K8M3F7QPZRVWT6YBHCE", "email": "jane@example.com", "display_name": "Jane Smith", "role": "user", "email_verified": false, "created_at": "2026-03-15T10:00:00Z" }, "access_token": "eyJhbGciOiJSUzI1NiJ9...", "refresh_token": "rt_01JN2X4K8M3F7QPZRVWT6YBHCE", "expires_in": 900}A verification email is sent automatically. The user must verify their email before accessing host features.
Errors
Section titled “Errors”| Code | Status | Description |
|---|---|---|
validation_error | 400 | Missing or invalid fields |
conflict | 409 | Email already registered |
rate_limited | 429 | Too many registration attempts |
POST /auth/login
Section titled “POST /auth/login”Authenticate with email and password.
Rate limit: 5 requests per 15 minutes per IP.
Request
Section titled “Request”POST /v1/auth/loginContent-Type: application/json{ "email": "jane@example.com", "password": "SecureP@ssw0rd!"}Response
Section titled “Response”HTTP/1.1 200 OKContent-Type: application/json{ "user": { "id": "01JN2X4K8M3F7QPZRVWT6YBHCE", "email": "jane@example.com", "display_name": "Jane Smith", "role": "verified_user", "email_verified": true, "created_at": "2026-03-15T10:00:00Z" }, "access_token": "eyJhbGciOiJSUzI1NiJ9...", "refresh_token": "rt_01JN2X4K8M3F7QPZRVWT6YBHCE", "expires_in": 900}Errors
Section titled “Errors”| Code | Status | Description |
|---|---|---|
invalid_credentials | 401 | Email or password is incorrect |
rate_limited | 429 | Too many login attempts |
POST /auth/refresh
Section titled “POST /auth/refresh”Exchange a refresh token for a new access token. The refresh token is rotated on each call — the old refresh token is invalidated immediately.
Request
Section titled “Request”POST /v1/auth/refreshContent-Type: application/json{ "refresh_token": "rt_01JN2X4K8M3F7QPZRVWT6YBHCE"}Response
Section titled “Response”HTTP/1.1 200 OKContent-Type: application/json{ "access_token": "eyJhbGciOiJSUzI1NiJ9...", "refresh_token": "rt_01JN2X5L9N4G8RQASWU7ZCIDFE", "expires_in": 900}Errors
Section titled “Errors”| Code | Status | Description |
|---|---|---|
invalid_token | 401 | Refresh token is invalid, expired, or already used |
POST /auth/logout
Section titled “POST /auth/logout”Invalidate the current session. The refresh token is revoked and cannot be used again.
Requires: Authorization: Bearer <access_token>
Request
Section titled “Request”POST /v1/auth/logoutAuthorization: Bearer eyJhbGciOiJSUzI1NiJ9...Content-Type: application/json{ "refresh_token": "rt_01JN2X5L9N4G8RQASWU7ZCIDFE"}Response
Section titled “Response”HTTP/1.1 204 No ContentErrors
Section titled “Errors”| Code | Status | Description |
|---|---|---|
unauthorized | 401 | Missing or invalid access token |
Code Examples
Section titled “Code Examples”# Registercurl -X POST https://api.vidivo.app/v1/auth/register \ -H "Content-Type: application/json" \ -d '{"email":"jane@example.com","password":"SecureP@ssw0rd!","display_name":"Jane Smith"}'
# Logincurl -X POST https://api.vidivo.app/v1/auth/login \ -H "Content-Type: application/json" \ -d '{"email":"jane@example.com","password":"SecureP@ssw0rd!"}'
# Refreshcurl -X POST https://api.vidivo.app/v1/auth/refresh \ -H "Content-Type: application/json" \ -d '{"refresh_token":"rt_01JN2X4K8M3F7QPZRVWT6YBHCE"}'
# Logoutcurl -X POST https://api.vidivo.app/v1/auth/logout \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiJ9..." \ -H "Content-Type: application/json" \ -d '{"refresh_token":"rt_01JN2X5L9N4G8RQASWU7ZCIDFE"}'const API = 'https://api.vidivo.app/v1';
// Loginconst { access_token, refresh_token } = await fetch(`${API}/auth/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: 'jane@example.com', password: 'SecureP@ssw0rd!' }),}).then(r => r.json());
// Authenticated requestconst profile = await fetch(`${API}/users/me`, { headers: { Authorization: `Bearer ${access_token}` },}).then(r => r.json());
// Refresh when access token expiresconst refreshed = await fetch(`${API}/auth/refresh`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ refresh_token }),}).then(r => r.json());package main
import ( "bytes" "encoding/json" "fmt" "net/http")
const baseURL = "https://api.vidivo.app/v1"
type LoginRequest struct { Email string `json:"email"` Password string `json:"password"`}
type AuthResponse struct { AccessToken string `json:"access_token"` RefreshToken string `json:"refresh_token"` ExpiresIn int `json:"expires_in"`}
func login(email, password string) (*AuthResponse, error) { body, _ := json.Marshal(LoginRequest{Email: email, Password: password}) resp, err := http.Post(baseURL+"/auth/login", "application/json", bytes.NewReader(body)) if err != nil { return nil, err } defer resp.Body.Close()
var auth AuthResponse json.NewDecoder(resp.Body).Decode(&auth) return &auth, nil}
func main() { auth, err := login("jane@example.com", "SecureP@ssw0rd!") if err != nil { panic(err) } fmt.Printf("Access token: %s\n", auth.AccessToken)}Token Lifecycle
Section titled “Token Lifecycle” Register / Login │ ▼ access_token (15 min TTL) refresh_token (30 day TTL) │ │ access_token expires ▼ POST /auth/refresh ├── Old refresh_token invalidated └── New access_token + refresh_token issued │ │ logout / session revoked ▼ refresh_token invalidated All sessions for token invalidatedJWT Claims
Section titled “JWT Claims”Access tokens contain the following claims:
{ "sub": "01JN2X4K8M3F7QPZRVWT6YBHCE", "email": "jane@example.com", "role": "verified_user", "iat": 1710000000, "exp": 1710000900, "iss": "api.vidivo.app"}| Claim | Description |
|---|---|
sub | User ID (ULID format) |
email | User email address |
role | Current role: guest, user, verified_user, host, admin |
iat | Issued-at timestamp (Unix) |
exp | Expiry timestamp (Unix) |
iss | Issuer — always api.vidivo.app |