Skip to main content

Overview

AudioPod AI supports multiple authentication methods with advanced security features:
  • JWT Authentication: Session-based authentication with device tracking
  • API Key Authentication: Server-to-server integration with scoped permissions
  • OAuth Integration: Google and GitHub single sign-on with account linking
  • Session Management: Multi-device session tracking and management
  • Security Features: CAPTCHA protection, rate limiting, and abuse prevention
  • Phone Verification: SMS-based phone number verification
  • Device Management: Trust and security management for user devices
All authenticated endpoints require either a valid JWT token in the Authorization: Bearer {token} header or an API key in the X-API-Key:{" "} {api_key} header.

JWT Authentication

Login

Authenticate with email/password to receive JWT tokens.
  • POST
  • Python
  • cURL
POST /api/v1/auth/token
Content-Type: application/x-www-form-urlencoded

username=user@example.com&password=secure_password
Response:
{
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "user@example.com",
    "full_name": "John Doe",
    "is_active": true,
    "is_verified": true,
    "created_at": "2024-01-15T10:30:00Z",
    "updated_at": "2024-01-15T10:30:00Z",
    "image": null,
    "phone_number": null,
    "phone_verified": false,
    "user_type": null,
    "audio_usage": null,
    "credits": {
      "credits_balance": 1500,
      "payg_balance": 500,
      "total_available_credits": 2000,
      "credits_used_today": 0,
      "daily_limit": 10000,
      "last_reset_at": "2024-01-15T00:00:00Z"
    },
    "subscription": {
      "plan_id": "price_free",
      "plan_name": "Free",
      "is_free_plan": true,
      "status": "active",
      "current_period_start": "2024-01-15T10:30:00Z",
      "current_period_end": "2024-02-15T10:30:00Z",
      "cancel_at": null
    },
    "is_eligible_for_first_time_discount": true,
    "first_time_discount_active": true
  },
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "expires_in": 3600
}

Refresh Token

Refresh an expired access token using the refresh token.
  • POST
  • Python
POST /api/v1/auth/refresh
Content-Type: application/json

{
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Logout

Invalidate current tokens and end the session.
  • POST
  • Python
POST /api/v1/auth/logout
Authorization: Bearer {access_token}

OAuth Authentication

Google OAuth

Authenticate or register using Google account. This endpoint handles both new user registration and existing user login.
  • POST
  • Python
  • cURL
POST /api/v1/auth/oauth/google
Content-Type: application/json

{
  "profile": {
    "email": "user@example.com",
    "name": "John Doe",
    "picture": "https://lh3.googleusercontent.com/a/..."
  },
  "account": {
    "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6...",
    "access_token": "ya29.a0AfH6SMC...",
    "providerAccountId": "1234567890",
    "type": "oauth",
    "expires_at": 1640995200
  },
  "browser_fingerprint": "optional-fingerprint-string"
}

GitHub OAuth

Authenticate or register using GitHub account. Same response format as Google OAuth.
  • POST
  • Python
POST /api/v1/auth/oauth/github
Content-Type: application/json

{
  "profile": {
    "email": "user@example.com",
    "name": "John Doe",
    "picture": "https://avatars.githubusercontent.com/u/..."
  },
  "account": {
    "access_token": "ghp_abcdef1234567890",
    "providerAccountId": "987654321",
    "type": "oauth"
  }
}
OAuth Response (for both Google and GitHub): Returns the same format as login - complete user object with tokens:
{
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "user@example.com",
    "full_name": "John Doe",
    "image": "https://lh3.googleusercontent.com/a/...",
    "is_active": true,
    "is_verified": true,
    "created_at": "2024-01-15T10:30:00Z",
    "credits": {
      "credits_balance": 5000,
      "payg_balance": 0,
      "total_available_credits": 5000
    },
    "subscription": {
      "plan_name": "Free",
      "is_free_plan": true,
      "status": "active"
    }
  },
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "expires_in": 3600
}

API Key Authentication

Generate API Key

Create a new API key for programmatic access.
  • POST
  • Python
POST /api/v1/auth/api-keys
Authorization: Bearer {access_token}
Content-Type: application/json

{
  "name": "Production API Key",
  "scopes": ["voice:read", "voice:write"]
}
Response:
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "Production API Key",
  "api_key": "ap_live_sk_1234567890abcdef",
  "description": "API key for production environment",
  "status": "active",
  "created_at": "2024-01-15T10:30:00Z",
  "last_used_at": null,
  "revoked_at": null
}

List API Keys

Get all API keys for the authenticated user.
  • GET
  • Python
GET /api/v1/auth/api-keys?status=active
Authorization: Bearer {access_token}

Revoke API Key

Disable an API key permanently.
  • DELETE
  • Python
DELETE /api/v1/auth/api-keys/{key_id}
Authorization: Bearer {access_token}

User Registration

Step 1: Initiate Registration

Start the registration process and receive verification code.
  • POST
  • Python
POST /api/v1/auth/initiate-registration
Content-Type: application/json

{
  "email": "newuser@example.com",
  "password": "secure_password123",
  "full_name": "Jane Doe"
}
Response:
{
  "message": "Verification code sent to email",
  "email": "newuser@example.com"
}

Step 2: Verify Registration

Complete registration with verification code from email.
  • POST
  • Python
POST /api/v1/auth/verify-registration
Content-Type: application/json

{
  "email": "newuser@example.com",
  "verification_code": "123456"
}
Response:
{
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "newuser@example.com",
    "full_name": "Jane Doe",
    "image": null,
    "phone_number": null,
    "phone_verified": false,
    "is_active": true,
    "is_verified": true,
    "created_at": "2024-01-15T10:30:00Z",
    "updated_at": "2024-01-15T10:30:00Z",
    "credits": {
      "credits_balance": 5000,
      "payg_balance": 0,
      "total_available_credits": 5000,
      "credits_used_today": 0,
      "daily_limit": 10000,
      "last_reset_at": "2024-01-15T00:00:00Z"
    },
    "subscription": {
      "plan_id": "price_free",
      "plan_name": "Free",
      "is_free_plan": true,
      "status": "active",
      "current_period_start": "2024-01-15T10:30:00Z",
      "current_period_end": "2024-02-15T10:30:00Z",
      "cancel_at": null
    },
    "is_eligible_for_first_time_discount": true,
    "first_time_discount_active": true
  },
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "expires_in": 3600
}

Password Reset

Request and confirm password reset.
  • POST
  • Python
POST /api/v1/auth/forgot-password
Content-Type: application/json

{
  "email": "user@example.com"
}

User Profile Management

Get Current User

Retrieve complete information about the authenticated user including credits, subscription, and security settings.
  • GET
  • Python
GET /api/v1/auth/me
Authorization: Bearer {access_token}
Response:
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "email": "user@example.com",
  "full_name": "John Doe",
  "image": "https://lh3.googleusercontent.com/a/...",
  "phone_number": "+1234567890",
  "phone_verified": true,
  "user_type": "individual",
  "audio_usage": "personal",
  "is_active": true,
  "is_verified": true,
  "created_at": "2024-01-15T10:30:00Z",
  "updated_at": "2024-01-15T11:00:00Z",
  "credits": {
    "credits_balance": 1500,
    "payg_balance": 500,
    "total_available_credits": 2000,
    "credits_used_today": 150,
    "daily_limit": 10000,
    "last_reset_at": "2024-01-15T00:00:00Z"
  },
  "subscription": {
    "plan_id": "price_pro_monthly",
    "plan_name": "Pro",
    "is_free_plan": false,
    "status": "active",
    "current_period_start": "2024-01-15T00:00:00Z",
    "current_period_end": "2024-02-15T00:00:00Z",
    "cancel_at": null
  },
  "is_eligible_for_first_time_discount": false,
  "first_time_discount_active": false
}

Update Profile

Update user profile information.
  • PATCH
  • Python
PATCH /api/v1/auth/me
Authorization: Bearer {access_token}
Content-Type: application/json

{
  "full_name": "Updated Name",
  "user_type": "individual",
  "audio_usage": "personal",
  "phone_number": "+1234567890",
  "country_code": "US"
}
Updating phone number will reset phone verification status. You’ll need to verify the new number using the phone verification endpoints.

Session Management

Validate Current Session

Check if the current session is valid and get detailed session information.
  • GET
  • Python
GET /api/v1/auth/session/validate
Authorization: Bearer {access_token}
Response:
{
  "is_valid": true,
  "session_info": {
    "session_id": "sess_abc123",
    "user_id": "550e8400-e29b-41d4-a716-446655440000",
    "device_info": "Chrome on Windows",
    "ip_address": "192.168.1.1",
    "created_at": "2024-01-15T10:30:00Z",
    "last_active": "2024-01-15T11:00:00Z",
    "expires_at": "2024-01-15T16:30:00Z",
    "is_current": true
  },
  "user": { /* Complete user object */ },
  "expires_in": 18000,
  "needs_refresh": false
}

List Active Sessions

View and manage all your active sessions across devices.
  • GET
  • Python
GET /api/v1/auth/sessions
Authorization: Bearer {access_token}
Response:
[
  {
    "session_id": "sess_abc123",
    "user_id": "550e8400-e29b-41d4-a716-446655440000",
    "device_info": "Chrome on Windows",
    "ip_address": "192.168.1.1",
    "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
    "created_at": "2024-01-15T10:30:00Z",
    "last_active": "2024-01-15T11:00:00Z",
    "expires_at": "2024-01-15T16:30:00Z",
    "is_current": true
  },
  {
    "session_id": "sess_def456",
    "user_id": "550e8400-e29b-41d4-a716-446655440000",
    "device_info": "Safari on iPhone",
    "ip_address": "10.0.0.1",
    "created_at": "2024-01-14T09:15:00Z",
    "last_active": "2024-01-14T22:45:00Z",
    "expires_at": "2024-01-15T04:15:00Z",
    "is_current": false
  }
]

Revoke Sessions

Revoke specific sessions or all other sessions for security.
  • POST
  • Python
POST /api/v1/auth/sessions/revoke
Authorization: Bearer {access_token}
Content-Type: application/json

{
  "session_id": "sess_def456",
  "revoke_all_others": false
}

Enhanced Token Refresh

Refresh access token with complete user data (alternative to basic refresh).
  • POST
  • Python
POST /api/v1/auth/refresh-enhanced
Content-Type: application/json

{
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Check Token Health

Check token validity and expiration status without full validation.
  • GET
  • Python
GET /api/v1/auth/token-health
Authorization: Bearer {access_token}
Response:
{
  "valid": true,
  "expired": false,
  "expires_in_seconds": 1800,
  "expires_in_minutes": 30,
  "should_refresh": false,
  "user_id": "550e8400-e29b-41d4-a716-446655440000"
}

Device Management

List User Devices

Get all devices and browsers the user has logged in from.
  • GET
  • Python
GET /api/v1/auth/devices?include_inactive=true
Authorization: Bearer {access_token}
Response:
{
  "devices": [
    {
      "id": "dev_abc123",
      "device_fingerprint": "fp_xyz789",
      "display_name": "Chrome on Windows",
      "browser": "Chrome",
      "os": "Windows",
      "device_type": "desktop",
      "ip_address": "192.168.1.1",
      "location": "New York, NY, US",
      "timezone": "America/New_York",
      "first_seen": "2024-01-10T10:00:00Z",
      "last_seen": "2024-01-15T11:00:00Z",
      "last_login_method": "password",
      "login_count": 15,
      "is_active": true,
      "is_current_session": true,
      "is_trusted": true,
      "is_blocked": false,
      "current_session_id": "sess_abc123"
    }
  ],
  "total_count": 3,
  "active_count": 2,
  "current_device": { /* Current device object */ },
  "trusted_count": 2
}

Security Features

CAPTCHA Protection

CAPTCHA challenges are automatically required based on IP reputation and activity patterns.

Check if CAPTCHA is Required

  • GET
  • Python
GET /api/v1/auth/captcha/required

Generate CAPTCHA Challenge

  • GET
  • Python
GET /api/v1/auth/captcha/generate
Response:
{
  "captcha_id": "capt_abc123",
  "question": "What is 7 + 15?",
  "expires_in": 300
}

Verify CAPTCHA Response

  • POST
  • Python
POST /api/v1/auth/captcha/verify
Content-Type: application/json

{
  "captcha_id": "capt_abc123",
  "answer": "22"
}

Phone Verification

Send Phone Verification Code

Send SMS verification code to user’s phone number.
  • POST
  • Python
POST /api/v1/auth/send-phone-verification
Authorization: Bearer {access_token}
Content-Type: application/json

{
  "phone_number": "+1234567890",
  "country_code": "US"
}

Verify Phone Number

Verify phone number with received OTP code.
  • POST
  • Python
POST /api/v1/auth/verify-phone
Authorization: Bearer {access_token}
Content-Type: application/json

{
  "phone_number": "+1234567890",
  "otp_code": "123456"
}

Password Management

Change Password

Change user password (requires current password).
  • POST
  • Python
POST /api/v1/auth/change-password
Authorization: Bearer {access_token}
Content-Type: application/json

{
  "current_password": "current_password123",
  "new_password": "new_secure_password456"
}
Password changes automatically log out all other active sessions for security.

OAuth Account Management

Link additional OAuth providers to your account.
  • POST
  • Python
POST /api/v1/auth/account-providers
Authorization: Bearer {access_token}
Content-Type: application/json

{
  "provider": "google",
  "provider_account_id": "1234567890",
  "type": "oauth",
  "access_token": "ya29.a0AfH6SMC...",
  "id_token": "eyJhbGciOiJSUzI1NiIs..."
}

List Linked Providers

  • GET
  • Python
GET /api/v1/auth/account-providers
Authorization: Bearer {access_token}
  • DELETE
  • Python
DELETE /api/v1/auth/account-providers/{provider}
Authorization: Bearer {access_token}

Rate Limiting

Authentication endpoints have specific rate limits to prevent abuse:
EndpointRate LimitWindowNotes
/auth/initiate-registration5 requests1 minutePrevents spam registrations
/auth/verify-registration10 requests1 minutePrevents code brute force
/auth/forgot-password3 requests1 hourPrevents email flooding
/auth/reset-password5 requests1 hourPrevents token brute force
Additional Security:
  • CAPTCHA required after suspicious activity
  • Maximum 3 signups per device/IP combination
  • Email flood protection across all users
  • Automatic account flagging for review
Rate Limit Headers:
X-RateLimit-Limit: 5
X-RateLimit-Remaining: 4
X-RateLimit-Reset: 1640995200
Retry-After: 60

Error Handling

Authentication Error Responses

{
  "error": {
    "code": "invalid_credentials",
    "message": "Incorrect email or password"
  }
}
{
  "error": {
    "code": "token_expired",
    "message": "Access token has expired",
    "suggestion": "Use refresh token to get a new access token"
  }
}
{
  "error": {
    "code": "invalid_token",
    "message": "Invalid token format or signature"
  }
}
{
  "error": {
    "code": "user_not_found",
    "message": "User not found"
  }
}

Registration Error Responses

{
  "error": {
    "code": "email_already_registered",
    "message": "This email address is already registered."
  }
}
{
  "error": {
    "code": "invalid_verification_code",
    "message": "Invalid email or verification code."
  }
}
{
  "error": {
    "code": "verification_code_expired",
    "message": "Verification code has expired. Please register again."
  }
}
{
  "error": {
    "code": "too_many_signups",
    "message": "Signup limit reached for this device or network."
  }
}

OAuth Error Responses

{
  "error": {
    "code": "provider_not_supported",
    "message": "Unsupported provider: facebook"
  }
}
{
  "error": {
    "code": "oauth_verification_failed",
    "message": "Invalid OAuth token data"
  }
}

Security Error Responses

{
  "detail": "Security verification required. Please complete the CAPTCHA challenge.",
  "headers": {
    "X-Captcha-Required": "true"
  }
}
{
  "detail": "Invalid security verification. Please try again.",
  "headers": {
    "X-Captcha-Required": "true"
  }
}
{
  "error": {
    "code": "password_recently_used",
    "message": "Cannot reuse recent passwords"
  }
}
{
  "error": {
    "code": "invalid_password",
    "message": "Incorrect current password"
  }
}

Rate Limiting and System Errors

{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Too many requests",
    "retry_after": 60
  }
}
Headers:
X-RateLimit-Limit: 5
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1640995200
Retry-After: 60
{
  "error": {
    "code": "system_error",
    "message": "Failed to process request",
    "details": {
      "error": "Internal server error details"
    }
  }
}
{
  "error": {
    "code": "validation_error",
    "message": "Invalid input data",
    "details": {
      "email": ["Invalid email format"],
      "password": ["Password must be at least 8 characters"]
    }
  }
}

Error Response Headers

Authentication endpoints may include additional headers:
HeaderDescriptionExample
X-Captcha-RequiredCAPTCHA verification needed"true"
X-RateLimit-LimitRequest limit per window5
X-RateLimit-RemainingRemaining requests in window4
X-RateLimit-ResetWindow reset timestamp1640995200
Retry-AfterSeconds to wait when rate limited60

Scopes and Permissions

Available Scopes

API keys can be granted specific scopes to limit access:
ScopeDescription
voice:readList and read voice data
voice:writeCreate and modify voices
voice:generateGenerate speech with voices
music:readAccess music generation data
music:generateGenerate music content
translation:useUse translation services
account:readRead account information
account:writeModify account settings
credits:readView credit balance
admin:*Administrative access

Scope Inheritance

Some scopes include others:
  • voice:write includes voice:read
  • admin:* includes all scopes
  • account:write includes account:read

Integration Examples

Web Application (React)

// React authentication hook
import { useState, useEffect } from "react";

export function useAuth() {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  const login = async (email, password) => {
    const response = await fetch("/api/v1/auth/token", {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: new URLSearchParams({ username: email, password }),
    });

    if (response.ok) {
      const data = await response.json();
      localStorage.setItem("access_token", data.access_token);
      localStorage.setItem("refresh_token", data.refresh_token);
      setUser(data.user);
      return true;
    }
    return false;
  };

  const logout = async () => {
    await fetch("/api/v1/auth/logout", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${localStorage.getItem("access_token")}`,
      },
    });

    localStorage.removeItem("access_token");
    localStorage.removeItem("refresh_token");
    setUser(null);
  };

  return { user, login, logout, loading };
}

Server-to-Server (Python)

# Python client with API key authentication
import requests

class AudioPodClient:
    def __init__(self, api_key):
        self.api_key = api_key
        self.base_url = "https://api.audiopod.ai/api/v1"
        self.session = requests.Session()
        self.session.headers.update({
            "X-API-Key": api_key,
            "User-Agent": "AudioPod-Python-Client/1.0"
        })

    def generate_speech(self, text, voice_id="aura-en-female"):
        response = self.session.post(
            f"{self.base_url}/voice/clone/",
            json={
                "input_text": text,
                "voice_id": voice_id
            }
        )
        response.raise_for_status()
        return response.json()

# Usage
client = AudioPodClient("ap_live_sk_your_api_key")
result = client.generate_speech("Hello, world!")

Best Practices

Security Recommendations

  1. Store tokens securely: Use secure storage for refresh tokens
  2. Implement token rotation: Regularly refresh access tokens
  3. Use HTTPS only: Never send tokens over unencrypted connections
  4. Validate tokens server-side: Always verify tokens on your backend
  5. Implement logout: Properly invalidate tokens when users log out
  6. Use minimal scopes: Grant only necessary permissions to API keys
  7. Monitor usage: Track API key usage and revoke suspicious keys

Error Handling

# Robust error handling example
import requests
from requests.exceptions import RequestException

def handle_auth_request(func, *args, **kwargs):
    try:
        response = func(*args, **kwargs)
        response.raise_for_status()
        return response.json()
    except requests.exceptions.Timeout:
        raise AuthError("Request timed out")
    except requests.exceptions.ConnectionError:
        raise AuthError("Connection failed")
    except requests.exceptions.HTTPError as e:
        if e.response.status_code == 401:
            raise AuthError("Invalid credentials")
        elif e.response.status_code == 429:
            raise AuthError("Rate limit exceeded")
        else:
            raise AuthError(f"HTTP error: {e.response.status_code}")
    except RequestException:
        raise AuthError("Unexpected error occurred")

Token Management

# Automatic token refresh implementation
import time
import jwt

class TokenManager:
    def __init__(self, access_token, refresh_token):
        self.access_token = access_token
        self.refresh_token = refresh_token

    def get_valid_token(self):
        if self._is_token_expired(self.access_token):
            self._refresh_access_token()
        return self.access_token

    def _is_token_expired(self, token):
        try:
            payload = jwt.decode(token, options={"verify_signature": False})
            return payload['exp'] < time.time() + 60  # Refresh 1 min before expiry
        except:
            return True

    def _refresh_access_token(self):
        response = requests.post(
            "https://api.audiopod.ai/api/v1/auth/refresh",
            json={"refresh_token": self.refresh_token}
        )

        if response.status_code == 200:
            data = response.json()
            self.access_token = data["access_token"]
        else:
            raise AuthError("Failed to refresh token")