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 live under /v1/auth/ and are unauthenticated (no Bearer token required).
POST /v1/auth/register
Section titled “POST /v1/auth/register”Create a new user account. A verification email is sent automatically.
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}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 /v1/auth/login
Section titled “POST /v1/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 /v1/auth/refresh
Section titled “POST /v1/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 /v1/auth/logout
Section titled “POST /v1/auth/logout”Invalidate the current session. The refresh token is revoked and cannot be used again.
Request
Section titled “Request”POST /v1/auth/logoutContent-Type: application/json{ "refresh_token": "rt_01JN2X5L9N4G8RQASWU7ZCIDFE"}Response
Section titled “Response”HTTP/1.1 200 OKContent-Type: application/json{ "message": "logged out successfully"}POST /v1/auth/verify-email
Section titled “POST /v1/auth/verify-email”Verify a user’s email address using the token from the verification email.
Request
Section titled “Request”POST /v1/auth/verify-emailContent-Type: application/json{ "token": "verify_abc123def456"}Response
Section titled “Response”HTTP/1.1 200 OKContent-Type: application/json{ "message": "email verified successfully"}Errors
Section titled “Errors”| Code | Status | Description |
|---|---|---|
invalid_token | 401 | Token is invalid or expired |
POST /v1/auth/password/reset
Section titled “POST /v1/auth/password/reset”Request a password reset email. Always returns the same message to prevent user enumeration.
Rate limit: 10 requests per hour per IP.
Request
Section titled “Request”POST /v1/auth/password/resetContent-Type: application/json{ "email": "jane@example.com"}Response
Section titled “Response”HTTP/1.1 200 OKContent-Type: application/json{ "message": "if an account with that email exists, a password reset link has been sent"}POST /v1/auth/password/confirm
Section titled “POST /v1/auth/password/confirm”Set a new password using the token from the password reset email.
Request
Section titled “Request”POST /v1/auth/password/confirmContent-Type: application/json{ "token": "reset_abc123def456", "new_password": "NewSecureP@ss!"}Response
Section titled “Response”HTTP/1.1 200 OKContent-Type: application/json{ "message": "password has been reset successfully"}Errors
Section titled “Errors”| Code | Status | Description |
|---|---|---|
invalid_token | 401 | Reset token is invalid or expired |
validation_error | 400 | Password does not meet requirements |
POST /v1/auth/google
Section titled “POST /v1/auth/google”Authenticate with a Google OAuth ID token. Creates a new account if the email is not yet registered, or links the Google account if the email already exists.
Rate limit: 5 requests per 15 minutes per IP.
Request
Section titled “Request”POST /v1/auth/googleContent-Type: application/json{ "id_token": "eyJhbGciOiJSUzI1NiJ9..."}| Field | Type | Required | Description |
|---|---|---|---|
id_token | string | Yes | Google OAuth2 ID token from the client SDK |
Response
Section titled “Response”Same format as POST /v1/auth/login.
Errors
Section titled “Errors”| Code | Status | Description |
|---|---|---|
invalid_token | 401 | Google ID token is invalid or expired |
rate_limited | 429 | Too many login attempts |
POST /v1/auth/apple
Section titled “POST /v1/auth/apple”Authenticate with an Apple Sign-In ID token. Creates a new account if not registered, or links the Apple account if the email already exists.
Rate limit: 5 requests per 15 minutes per IP.
Request
Section titled “Request”POST /v1/auth/appleContent-Type: application/json{ "id_token": "eyJhbGciOiJSUzI1NiJ9...", "display_name": "Jane Smith"}| Field | Type | Required | Description |
|---|---|---|---|
id_token | string | Yes | Apple Sign-In identity token |
display_name | string | No | Display name (Apple may not share this on subsequent logins) |
Response
Section titled “Response”Same format as POST /v1/auth/login.
Errors
Section titled “Errors”| Code | Status | Description |
|---|---|---|
invalid_token | 401 | Apple ID token is invalid or expired |
rate_limited | 429 | Too many login attempts |
POST /v1/auth/guest-session
Section titled “POST /v1/auth/guest-session”Create a guest session for an unauthenticated caller. Guest sessions allow joining a call without registering an account.
Request
Section titled “Request”POST /v1/auth/guest-sessionContent-Type: application/json{ "display_name": "Alex"}| Field | Type | Required | Description |
|---|---|---|---|
display_name | string | No | Guest’s display name shown during the call |
Response
Section titled “Response”HTTP/1.1 201 CreatedContent-Type: application/json{ "guest_session_id": "gs_a1b2c3d4e5f6", "access_token": "eyJhbGciOiJSUzI1NiJ9...", "expires_in": 86400}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 "Content-Type: application/json" \ -d '{"refresh_token":"rt_01JN2X5L9N4G8RQASWU7ZCIDFE"}'
# Google logincurl -X POST https://api.vidivo.app/v1/auth/google \ -H "Content-Type: application/json" \ -d '{"id_token":"eyJhbGciOiJSUzI1NiJ9..."}'
# Guest sessioncurl -X POST https://api.vidivo.app/v1/auth/guest-session \ -H "Content-Type: application/json" \ -d '{"display_name":"Alex"}'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 / OAuth | v access_token (15 min TTL) refresh_token (30 day TTL) | | access_token expires v POST /v1/auth/refresh +-- Old refresh_token invalidated +-- New access_token + refresh_token issued | | logout / session revoked v 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 (UUID 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 |