This guide walks through the complete authentication flow for Freddy API, from initial login to making authenticated API requests.
Freddy uses a two-step authentication process:
- Login - Validate credentials and receive email verification code
- Verify - Confirm email code and receive JWT tokens
- Authenticate - Use Bearer token for API requests
- Refresh - Renew expired tokens without re-login
Send user credentials to initiate the login process.
Endpoint: POST /v1/auth/login
import requests
response = requests.post(
"https://api.aitronos.com/v1/auth/login",
json={
"email_or_username": "user@example.com",
"password": "your_secure_password"
}
)
data = response.json()
email_key = data["email_key"] # Save this for step 2const response = await fetch("https://api.aitronos.com/v1/auth/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email_or_username: "user@example.com",
password: "your_secure_password"
})
});
const data = await response.json();
const emailKey = data.email_key; // Save this for step 2Response:
{
"success": true,
"message": "Login credentials verified. Please check your email for verification code.",
"email_key": "uuid-12345678-1234-1234-1234-123456789abc",
"email": "user@example.com",
"requires_verification": true,
"next_step": "email_verification"
}The user receives a 4-digit verification code via email (expires in 5 minutes).
Submit the verification code received via email.
Endpoint: POST /v1/auth/verify
verification_code = 2290 # Code from email
response = requests.post(
"https://api.aitronos.com/v1/auth/verify",
json={
"email_key": email_key,
"verification_code": verification_code
}
)
data = response.json()
access_token = data["token"]
refresh_token = data["refreshToken"]
# Store tokens securelyconst verificationCode = 2290; // Code from email
const response = await fetch("https://api.aitronos.com/v1/auth/verify", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email_key: emailKey,
verification_code: verificationCode
})
});
const data = await response.json();
const accessToken = data.token;
const refreshToken = data.refreshToken;
// Store tokens securelyResponse:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer",
"expires_in": 86400,
"user": {
"id": "usr_1e60b7a014eb4f0c9f335ce11ebc0816",
"email": "user@example.com",
"verified": true
}
}Use the Bearer token in the Authorization header for all API requests.
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
# Create a response
response = requests.post(
"https://api.aitronos.com/v1/responses",
headers=headers,
json={
"model": "gpt-4",
"messages": [{"role": "user", "content": "Hello!"}]
}
)const headers = {
"Authorization": `Bearer ${accessToken}`,
"Content-Type": "application/json"
};
// Create a response
const response = await fetch("https://api.aitronos.com/v1/responses", {
method: "POST",
headers: headers,
body: JSON.stringify({
model: "gpt-4",
messages: [{ role: "user", content: "Hello!" }]
})
});curl -X POST "https://api.aitronos.com/v1/responses" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4",
"messages": [{"role": "user", "content": "Hello!"}]
}'When the access token expires (after 24 hours), use the refresh token to get a new one.
Endpoint: POST /v1/auth/refresh
response = requests.post(
"https://api.aitronos.com/v1/auth/refresh",
json={"refresh_token": refresh_token}
)
data = response.json()
access_token = data["token"] # New access tokenconst response = await fetch("https://api.aitronos.com/v1/auth/refresh", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
refresh_token: refreshToken
})
});
const data = await response.json();
const newAccessToken = data.token;Response:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"device_id": "device-123"
}Here's a complete Python class that handles the entire flow:
import requests
from typing import Optional
class FreddyAuth:
def __init__(self):
self.base_url = "https://api.aitronos.com/v1"
self.access_token: Optional[str] = None
self.refresh_token: Optional[str] = None
def login(self, email_or_username: str, password: str) -> str:
"""Step 1: Login and get email_key"""
response = requests.post(
f"{self.base_url}/auth/login",
json={
"email_or_username": email_or_username,
"password": password
}
)
response.raise_for_status()
data = response.json()
return data["email_key"]
def verify(self, email_key: str, verification_code: int):
"""Step 2: Verify email code and store tokens"""
response = requests.post(
f"{self.base_url}/auth/verify",
json={
"email_key": email_key,
"verification_code": verification_code
}
)
response.raise_for_status()
data = response.json()
self.access_token = data["token"]
self.refresh_token = data["refreshToken"]
return data
def refresh(self):
"""Step 4: Refresh access token"""
if not self.refresh_token:
raise ValueError("No refresh token available")
response = requests.post(
f"{self.base_url}/auth/refresh",
json={"refresh_token": self.refresh_token}
)
response.raise_for_status()
data = response.json()
self.access_token = data["token"]
return data
def get_headers(self) -> dict:
"""Get headers for authenticated requests"""
if not self.access_token:
raise ValueError("Not authenticated. Call login() and verify() first.")
return {
"Authorization": f"Bearer {self.access_token}",
"Content-Type": "application/json"
}
def create_response(self, model: str, messages: list):
"""Step 3: Make authenticated API request"""
response = requests.post(
f"{self.base_url}/responses",
headers=self.get_headers(),
json={"model": model, "messages": messages}
)
# Auto-refresh on 401
if response.status_code == 401:
self.refresh()
response = requests.post(
f"{self.base_url}/responses",
headers=self.get_headers(),
json={"model": model, "messages": messages}
)
response.raise_for_status()
return response.json()
# Usage
auth = FreddyAuth()
# Step 1: Login
email_key = auth.login("user@example.com", "password123")
print(f"Check your email for verification code")
# Step 2: Verify (user enters code from email)
verification_code = int(input("Enter verification code: "))
auth.verify(email_key, verification_code)
# Step 3: Make API calls
result = auth.create_response(
model="gpt-4",
messages=[{"role": "user", "content": "Hello!"}]
)
print(result)class FreddyAuth {
constructor() {
this.baseUrl = "https://api.aitronos.com/v1";
this.accessToken = null;
this.refreshToken = null;
}
async login(emailOrUsername, password) {
const response = await fetch(`${this.baseUrl}/auth/login`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email_or_username: emailOrUsername,
password: password
})
});
if (!response.ok) throw new Error("Login failed");
const data = await response.json();
return data.email_key;
}
async verify(emailKey, verificationCode) {
const response = await fetch(`${this.baseUrl}/auth/verify`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email_key: emailKey,
verification_code: verificationCode
})
});
if (!response.ok) throw new Error("Verification failed");
const data = await response.json();
this.accessToken = data.token;
this.refreshToken = data.refreshToken;
return data;
}
async refresh() {
if (!this.refreshToken) {
throw new Error("No refresh token available");
}
const response = await fetch(`${this.baseUrl}/auth/refresh`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ refresh_token: this.refreshToken })
});
if (!response.ok) throw new Error("Token refresh failed");
const data = await response.json();
this.accessToken = data.token;
return data;
}
getHeaders() {
if (!this.accessToken) {
throw new Error("Not authenticated");
}
return {
"Authorization": `Bearer ${this.accessToken}`,
"Content-Type": "application/json"
};
}
async createResponse(model, messages) {
let response = await fetch(`${this.baseUrl}/responses`, {
method: "POST",
headers: this.getHeaders(),
body: JSON.stringify({ model, messages })
});
// Auto-refresh on 401
if (response.status === 401) {
await this.refresh();
response = await fetch(`${this.baseUrl}/responses`, {
method: "POST",
headers: this.getHeaders(),
body: JSON.stringify({ model, messages })
});
}
if (!response.ok) throw new Error("API request failed");
return response.json();
}
}
// Usage
const auth = new FreddyAuth();
// Step 1: Login
const emailKey = await auth.login("user@example.com", "password123");
console.log("Check your email for verification code");
// Step 2: Verify
const verificationCode = 2290; // From email
await auth.verify(emailKey, verificationCode);
// Step 3: Make API calls
const result = await auth.createResponse("gpt-4", [
{ role: "user", content: "Hello!" }
]);
console.log(result);| Token Type | Expiration | Purpose |
|---|---|---|
| Access Token | 24 hours | API authentication |
| Refresh Token | 30 days | Renew access tokens |
| Email Key | 5 minutes | Email verification session |
| Verification Code | 5 minutes | One-time email code |
Web Applications:
- Store tokens in memory or secure HTTP-only cookies
- Never use localStorage for production apps
- Clear tokens on logout
Mobile/Desktop:
- Use secure storage (Keychain, KeyStore)
- Encrypt tokens at rest
- Clear on app uninstall
def make_authenticated_request(auth, endpoint, data):
try:
response = requests.post(
f"{auth.base_url}/{endpoint}",
headers=auth.get_headers(),
json=data
)
if response.status_code == 401:
# Token expired, refresh and retry
auth.refresh()
response = requests.post(
f"{auth.base_url}/{endpoint}",
headers=auth.get_headers(),
json=data
)
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
if e.response.status_code == 401:
print("Authentication failed. Please login again.")
elif e.response.status_code == 403:
print("Permission denied.")
else:
print(f"Request failed: {e}")
raiseIf the code expires (5 minutes), request a new one:
Endpoint: POST /v1/auth/resend-email
response = requests.post(
"https://api.aitronos.com/v1/auth/resend-email",
json={"email_key": email_key}
){
"success": false,
"error": {
"code": "INVALID_CREDENTIALS",
"message": "Invalid email or password",
"status": 401
}
}{
"success": false,
"error": {
"code": "TOO_MANY_LOGIN_ATTEMPTS",
"message": "Too many login attempts. Please try again later",
"status": 429,
"details": {
"retry_after": 300
}
}
}For server-to-server or long-lived integrations, use API keys instead:
headers = {
"api-key": "ak_your_api_key_here",
"Content-Type": "application/json"
}
response = requests.post(
"https://api.aitronos.com/v1/responses",
headers=headers,
json={"model": "gpt-4", "messages": [...]}
)Get your API key from Freddy Hub.
- API Key Authentication - Alternative authentication method
- Rate Limiting - Understand API limits
- Error Handling - Handle API errors gracefully
- API Reference - Detailed endpoint documentation