Authentication
Creating an Account
To create an account, you need to send a POST request to our API with the account details. This will register a new account for your betting business.
- cURL
- JavaScript
- Python
- Rust
curl -X POST "$baseUrl/auth/register/account" \
-H "Content-Type: application/json" \
-d '{
"name": "My Betting Business",
"email": "business@example.com",
"password": "securepassword"
}'
const createAccount = async () => {
try {
const response = await fetch(`${baseUrl}/auth/register/account`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "My Betting Business",
email: "business@example.com",
password: "securepassword",
}),
});
const data = await response.json();
console.log("Account created:", data);
} catch (error) {
console.error("Error creating account:", error);
}
};
// Usage
createAccount();
import requests
import json
def create_account():
url = f"{baseUrl}/auth/register/account"
headers = {
'Content-Type': 'application/json'
}
payload = {
"name": "My Betting Business",
"email": "business@example.com",
"password": "securepassword"
}
response = requests.post(url, headers=headers, data=json.dumps(payload))
if response.status_code == 200:
print('Account created:', response.json())
else:
print('Error creating account:', response.text)
# Usage
create_account()
use reqwest::Client;
use serde::{Deserialize, Serialize};
#[derive(Serialize)]
struct AccountRequest {
name: String,
email: String,
password: String,
}
async fn create_account(client: &Client, base_url: &str)
-> Result<serde_json::Value, Box<dyn std::error::Error>> {
let account_request = AccountRequest {
name: "My Betting Business".to_string(),
email: "business@example.com".to_string(),
password: "securepassword".to_string(),
};
let response = client
.post(&format!("{}/auth/register/account", base_url))
.header("Content-Type", "application/json")
.json(&account_request)
.send()
.await?;
let account_data = response.json::<serde_json::Value>().await?;
println!("Account created: {:?}", account_data);
Ok(account_data)
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
// Create account
let account_data = create_account(&client, baseUrl).await?;
Ok(())
}
Upon successful creation, the API will respond with the account's details:
{
"message": "Account created successfully"
}
Logging In
To log in to your account, you need to send a POST request to our API with your email and password. This will authenticate your account and return a token.
- cURL
- JavaScript
- Python
- Rust
curl -X POST "$baseUrl/auth/login/account" \
-H "Content-Type: application/json" \
-d '{
"email": "business@example.com",
"password": "securepassword"
}'
const login = async () => {
try {
const response = await fetch(`${baseUrl}/auth/login/account`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: "business@example.com",
password: "securepassword",
}),
});
const data = await response.json();
console.log("Logged in:", data);
} catch (error) {
console.error("Error logging in:", error);
}
};
// Usage
login();
import requests
import json
def login():
url = f"{baseUrl}/auth/login/account"
headers = {
'Content-Type': 'application/json'
}
payload = {
"email": "business@example.com",
"password": "securepassword"
}
response = requests.post(url, headers=headers, data=json.dumps(payload))
if response.status_code == 200:
print('Logged in:', response.json())
else:
print('Error logging in:', response.text)
# Usage
login()
use reqwest::Client;
use serde::{Deserialize, Serialize};
#[derive(Serialize)]
struct LoginRequest {
email: String,
password: String,
}
async fn login(client: &Client, base_url: &str)
-> Result<serde_json::Value, Box<dyn std::error::Error>> {
let login_request = LoginRequest {
email: "business@example.com".to_string(),
password: "securepassword".to_string(),
};
let response = client
.post(&format!("{}/auth/login/account", base_url))
.header("Content-Type", "application/json")
.json(&login_request)
.send()
.await?;
let login_data = response.json::<serde_json::Value>().await?;
println!("Logged in: {:?}", login_data);
Ok(login_data)
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
// Log in
let login_data = login(&client, baseUrl).await?;
Ok(())
}
Upon successful login, the API will respond with the authentication token:
{
"data": {
"token": "OCFUBbMIX4PGXb4ROw5xKVC8kW8tGSBh"
},
"message": "Logged into account successfully"
}
Logging Out
To log out from your account, you need to send a POST request to our API. This will invalidate your authentication token.
- cURL
- JavaScript
- Python
- Rust
curl -X POST "$baseUrl/auth/logout/account?logout_all=true" \
-H "Authorization: Bearer $token" \
-H "Content-Type: application/json"
const logout = async (token) => {
try {
const response = await fetch(`${baseUrl}/auth/logout/account?logout_all=true`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
});
const data = await response.json();
console.log("Logged out:", data);
} catch (error) {
console.error("Error logging out:", error);
}
};
// Usage
const token = "your_auth_token"; // Replace with actual token
logout(token);
import requests
def logout(token):
url = f"{baseUrl}/auth/logout/account?logout_all=true"
headers = {
'Authorization': f"Bearer {token}",
'Content-Type': 'application/json'
}
response = requests.post(url, headers=headers)
if response.status_code == 200:
print('Logged out:', response.json())
else:
print('Error logging out:', response.text)
# Usage
token = 'your_auth_token' # Replace with actual token
logout(token)
use reqwest::Client;
use serde_json::Value;
async fn logout(client: &Client, base_url: &str, token: &str)
-> Result<Value, Box<dyn std::error::Error>> {
let response = client
.post(&format!("{}/auth/logout/account?logout_all=true", base_url))
.header("Authorization", format!("Bearer {}", token))
.header("Content-Type", "application/json")
.send()
.await?;
let logout_data = response.json::<Value>().await?;
println!("Logged out: {:?}", logout_data);
Ok(logout_data)
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
// Log out
let token = "your_auth_token"; // Replace with actual token
let logout_data = logout(&client, baseUrl, token).await?;
Ok(())
}
Upon successful logout, the API will respond with a confirmation message:
{
"message": "Logged out successfully"
}
Creating API Keys
To create API keys for your account, you need to send a POST request to our API. This will generate a new API key and secret for your account.
- cURL
- JavaScript
- Python
- Rust
curl -X POST "$baseUrl/auth/account/generate-keys" \
-H "Authorization: Bearer $token" \
-H "Content-Type: application/json"
const generateApiKeys = async (token) => {
try {
const response = await fetch(`${baseUrl}/auth/account/generate-keys`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
});
const data = await response.json();
console.log("API keys generated:", data);
} catch (error) {
console.error("Error generating API keys:", error);
}
};
// Usage
const token = "your_auth_token"; // Replace with actual token
generateApiKeys(token);
import requests
def generate_api_keys(token):
url = f"{baseUrl}/auth/account/generate-keys"
headers = {
'Authorization': f"Bearer {token}",
'Content-Type': 'application/json'
}
response = requests.post(url, headers=headers)
if response.status_code == 200:
print('API keys generated:', response.json())
else:
print('Error generating API keys:', response.text)
# Usage
token = 'your_auth_token' # Replace with actual token
generate_api_keys(token)
use reqwest::Client;
use serde_json::Value;
async fn generate_api_keys(client: &Client, base_url: &str, token: &str)
-> Result<Value, Box<dyn std::error::Error>> {
let response = client
.post(&format!("{}/auth/account/generate-keys", base_url))
.header("Authorization", format!("Bearer {}", token))
.header("Content-Type", "application/json")
.send()
.await?;
let api_keys_data = response.json::<Value>().await?;
println!("API keys generated: {:?}", api_keys_data);
Ok(api_keys_data)
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
// Generate API keys
let token = "your_auth_token"; // Replace with actual token
let api_keys_data = generate_api_keys(&client, baseUrl, token).await?;
Ok(())
}
Upon successful generation, the API will respond with the API key and secret:
{
"data": {
"api_key": "api_key_k4rBSsfzj6SyJbsKOT3YXRXsmKRZuYT4",
"api_secret": "api_secret_80d6bx3NNRsqELP6in2eVS56jSGyVNhiUtRMeImnUoJWc8DQYgLnwm1gH45PISQN",
"base64_encoded": "YXBpX2tleV9rNHJCU3Nmemo2U3lKYnNLT1QzWVhSWHNtS1JadVlUNDphcGlfc2VjcmV0XzgwZDZieDNOTlJzcUVMUDZpbjJlVlM1NmpTR3lWTmhpVXRSTWVJbW5Vb0pXYzhEUVlnTG53bTFnSDQ1UElTUU4="
},
"message": "Api keys generated successfully"
}
Verify Account Email
To verify your account email, you need to click on the verification link that was sent to your email address or use the verification token in a GET request to our API.
- cURL
- JavaScript
- Python
- Rust
curl -X GET "$baseUrl/auth/account/verify-email?token=your_verification_token"
const verifyEmail = async (verificationToken) => {
try {
const response = await fetch(`${baseUrl}/auth/account/verify-email?token=${verificationToken}`, {
method: "GET"
});
const data = await response.json();
console.log("Email verification response:", data);
} catch (error) {
console.error("Error verifying email:", error);
}
};
// Usage
const verificationToken = "your_verification_token"; // Token from the email
verifyEmail(verificationToken);
import requests
def verify_email(verification_token):
url = f"{baseUrl}/auth/account/verify-email?token={verification_token}"
response = requests.get(url)
if response.status_code == 200:
print('Email verified:', response.json())
else:
print('Error verifying email:', response.text)
# Usage
verification_token = 'your_verification_token' # Token from the email
verify_email(verification_token)
use reqwest::Client;
use serde_json::Value;
async fn verify_email(client: &Client, base_url: &str, verification_token: &str)
-> Result<Value, Box<dyn std::error::Error>> {
let url = format!("{}/auth/account/verify-email?token={}", base_url, verification_token);
let response = client
.get(&url)
.send()
.await?;
let verification_data = response.json::<Value>().await?;
println!("Email verification response: {:?}", verification_data);
Ok(verification_data)
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
// Verify email
let verification_token = "your_verification_token"; // Token from the email
let verification_data = verify_email(&client, baseUrl, verification_token).await?;
Ok(())
}
Upon successful verification, the API will respond with a confirmation message:
{
"message": "Email verified successfully"
}
Resend Verification Email
If you didn't receive the verification email or the token has expired, you can request a new verification email. You need to be authenticated to use this endpoint.
- cURL
- JavaScript
- Python
- Rust
curl -X POST "$baseUrl/auth/account/resend-verification-email" \
-H "Authorization: Bearer $token" \
-H "Content-Type: application/json"
const resendVerificationEmail = async (token) => {
try {
const response = await fetch(`${baseUrl}/auth/account/resend-verification-email`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
}
});
const data = await response.json();
console.log("Verification email response:", data);
} catch (error) {
console.error("Error resending verification email:", error);
}
};
// Usage
const token = "your_auth_token"; // Replace with actual token
resendVerificationEmail(token);
import requests
def resend_verification_email(token):
url = f"{baseUrl}/auth/account/resend-verification-email"
headers = {
'Authorization': f"Bearer {token}",
'Content-Type': 'application/json'
}
response = requests.post(url, headers=headers)
if response.status_code == 200:
print('Verification email sent:', response.json())
else:
print('Error sending verification email:', response.text)
# Usage
token = 'your_auth_token' # Replace with actual token
resend_verification_email(token)
use reqwest::Client;
use serde_json::Value;
async fn resend_verification_email(client: &Client, base_url: &str, token: &str)
-> Result<Value, Box<dyn std::error::Error>> {
let response = client
.post(&format!("{}/auth/account/resend-verification-email", base_url))
.header("Authorization", format!("Bearer {}", token))
.header("Content-Type", "application/json")
.send()
.await?;
let result = response.json::<Value>().await?;
println!("Verification email response: {:?}", result);
Ok(result)
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
// Resend verification email
let token = "your_auth_token"; // Replace with actual token
let result = resend_verification_email(&client, baseUrl, token).await?;
Ok(())
}
Upon successful request, the API will respond with a confirmation message:
{
"message": "Verification email sent successfully"
}
Password Reset
Authenticated users can reset their password by providing their current password and a new password. This endpoint requires authentication and validates the current password before allowing the reset.
Requirements
- User must be authenticated (using either Bearer token or API key)
- Current password must be provided and correct
- New password must be at least 8 characters long
- New password and password confirmation must match
Security Features
- ✅ Current Password Validation: Requires the current password (not a "forgot password" flow)
- ✅ Dual Authentication Support: Works with both Bearer tokens and API keys
- cURL
- JavaScript
- Python
- Rust
# Using Bearer Token
curl -X POST "$baseUrl/auth/account/reset-password" \
-H "Authorization: Bearer $token" \
-H "Content-Type: application/json" \
-d '{
"password": "current_password",
"new_password": "new_password_min_8_chars",
"password_confirmation": "new_password_min_8_chars"
}'
# Using API Key Authentication
curl -X POST "$baseUrl/auth/account/reset-password" \
-u "api_key:api_secret" \
-H "Content-Type: application/json" \
-d '{
"password": "current_password",
"new_password": "new_password_min_8_chars",
"password_confirmation": "new_password_min_8_chars"
}'
// Using Bearer Token
const resetPasswordWithToken = async (token, currentPassword, newPassword) => {
try {
const response = await fetch(`${baseUrl}/auth/account/reset-password`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
password: currentPassword,
new_password: newPassword,
password_confirmation: newPassword,
}),
});
const data = await response.json();
if (response.ok) {
console.log("Password reset successfully:", data);
} else {
console.error("Error resetting password:", data);
}
} catch (error) {
console.error("Error resetting password:", error);
}
};
// Using API Key Authentication
const resetPasswordWithApiKey = async (apiKey, apiSecret, currentPassword, newPassword) => {
try {
const response = await fetch(`${baseUrl}/auth/account/reset-password`, {
method: "POST",
headers: {
Authorization: `Basic ${btoa(`${apiKey}:${apiSecret}`)}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
password: currentPassword,
new_password: newPassword,
password_confirmation: newPassword,
}),
});
const data = await response.json();
if (response.ok) {
console.log("Password reset successfully:", data);
} else {
console.error("Error resetting password:", data);
}
} catch (error) {
console.error("Error resetting password:", error);
}
};
// Usage
const token = "your_auth_token";
const apiKey = "your_api_key";
const apiSecret = "your_api_secret";
resetPasswordWithToken(token, "current_password", "new_secure_password123");
resetPasswordWithApiKey(apiKey, apiSecret, "current_password", "new_secure_password123");
import requests
import json
from requests.auth import HTTPBasicAuth
def reset_password_with_token(token, current_password, new_password):
url = f"{baseUrl}/auth/account/reset-password"
headers = {
'Authorization': f"Bearer {token}",
'Content-Type': 'application/json'
}
payload = {
"password": current_password,
"new_password": new_password,
"password_confirmation": new_password
}
response = requests.post(url, headers=headers, data=json.dumps(payload))
if response.status_code == 200:
print('Password reset successfully:', response.json())
else:
print('Error resetting password:', response.text)
def reset_password_with_api_key(api_key, api_secret, current_password, new_password):
url = f"{baseUrl}/auth/account/reset-password"
headers = {
'Content-Type': 'application/json'
}
payload = {
"password": current_password,
"new_password": new_password,
"password_confirmation": new_password
}
response = requests.post(url,
auth=HTTPBasicAuth(api_key, api_secret),
headers=headers,
data=json.dumps(payload))
if response.status_code == 200:
print('Password reset successfully:', response.json())
else:
print('Error resetting password:', response.text)
# Usage
token = 'your_auth_token'
api_key = 'your_api_key'
api_secret = 'your_api_secret'
reset_password_with_token(token, 'current_password', 'new_secure_password123')
reset_password_with_api_key(api_key, api_secret, 'current_password', 'new_secure_password123')
use reqwest::Client;
use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Serialize)]
struct PasswordResetRequest {
password: String,
new_password: String,
password_confirmation: String,
}
async fn reset_password_with_token(
client: &Client,
base_url: &str,
token: &str,
current_password: &str,
new_password: &str
) -> Result<Value, Box<dyn std::error::Error>> {
let password_reset_request = PasswordResetRequest {
password: current_password.to_string(),
new_password: new_password.to_string(),
password_confirmation: new_password.to_string(),
};
let response = client
.post(&format!("{}/auth/account/reset-password", base_url))
.header("Authorization", format!("Bearer {}", token))
.header("Content-Type", "application/json")
.json(&password_reset_request)
.send()
.await?;
let result = response.json::<Value>().await?;
println!("Password reset with token: {:?}", result);
Ok(result)
}
async fn reset_password_with_api_key(
client: &Client,
base_url: &str,
api_key: &str,
api_secret: &str,
current_password: &str,
new_password: &str
) -> Result<Value, Box<dyn std::error::Error>> {
let password_reset_request = PasswordResetRequest {
password: current_password.to_string(),
new_password: new_password.to_string(),
password_confirmation: new_password.to_string(),
};
let response = client
.post(&format!("{}/auth/account/reset-password", base_url))
.basic_auth(api_key, Some(api_secret))
.header("Content-Type", "application/json")
.json(&password_reset_request)
.send()
.await?;
let result = response.json::<Value>().await?;
println!("Password reset with API key: {:?}", result);
Ok(result)
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
let base_url = "your_base_url"; // Replace with actual base URL
let token = "your_auth_token"; // Replace with actual token
let api_key = "your_api_key"; // Replace with actual API key
let api_secret = "your_api_secret"; // Replace with actual API secret
// Reset password with token
reset_password_with_token(&client, base_url, token, "current_password", "new_secure_password123").await?;
// Reset password with API key
reset_password_with_api_key(&client, base_url, api_key, api_secret, "current_password", "new_secure_password123").await?;
Ok(())
}
Upon successful password reset, the API will respond with a confirmation message:
{
"message": "Password reset successfully"
}
Error Responses
Validation Errors (400 Bad Request):
{
"message": [
"password should not be empty",
"new_password must be longer than or equal to 8 characters",
"password_confirmation should not be empty"
],
"error": "Bad Request",
"statusCode": 400
}
Incorrect Current Password (400 Bad Request):
{
"status": 400,
"error": "Current password is incorrect"
}
Password Mismatch (400 Bad Request):
{
"status": 400,
"error": "New password and confirmation do not match"
}
Unauthorized (401):
{
"message": "Unauthorized",
"statusCode": 401
}
Forgot Password Flow
For users who have forgotten their password, we provide a secure two-step process that uses email-based token verification. This flow is designed for unauthenticated users who cannot access their account.
Password Reset vs Forgot Password
| Feature | Password Reset | Forgot Password |
|---|---|---|
| Authentication Required | ✅ Required (Bearer token or API key) | ❌ No authentication needed |
| Current Password | ✅ Must provide current password | ❌ Not required |
| Email Verification | ❌ Not required | ✅ Uses email token |
| Use Case | Authenticated users changing password | Users who forgot their password |
| Security Level | High (requires current password) | High (email token validation) |
Complete Flow Overview
The forgot password process consists of two main steps:
- Request Password Reset Token - User provides email and receives a reset token
- Create New Password - User uses the token to set a new password
Security Features
- ✅ Email Enumeration Protection: Always returns success (doesn't reveal if email exists)
- ✅ Token Expiration: Reset tokens expire after 1 hour
- ✅ Automatic Cleanup: Previous tokens are deleted when new ones are requested
- ✅ Unique Tokens: Each token is a unique 8-character numeric code
- ✅ Email Notifications: Users receive confirmation emails for password changes
- ✅ Account Verification: Automatically verifies email if unverified
Step 1: Request Password Reset Token
The first step allows users to request a password reset token by providing their email address.
- cURL
- JavaScript
- Python
- Rust
curl -X POST "$baseUrl/auth/account/forgot-password" \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com"
}'
const requestPasswordReset = async (email) => {
try {
const response = await fetch(`${baseUrl}/auth/account/forgot-password`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: email,
}),
});
const data = await response.json();
if (response.ok) {
console.log("Password reset requested:", data);
// Always shows success for security
} else {
console.error("Error requesting password reset:", data);
}
} catch (error) {
console.error("Error requesting password reset:", error);
}
};
// Usage
requestPasswordReset("user@example.com");
import requests
import json
def request_password_reset(email):
url = f"{baseUrl}/auth/account/forgot-password"
headers = {
'Content-Type': 'application/json'
}
payload = {
"email": email
}
response = requests.post(url, headers=headers, data=json.dumps(payload))
if response.status_code == 200:
print('Password reset requested:', response.json())
# Always shows success for security
else:
print('Error requesting password reset:', response.text)
# Usage
request_password_reset('user@example.com')
use reqwest::Client;
use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Serialize)]
struct ForgotPasswordRequest {
email: String,
}
async fn request_password_reset(client: &Client, base_url: &str, email: &str)
-> Result<Value, Box<dyn std::error::Error>> {
let forgot_password_request = ForgotPasswordRequest {
email: email.to_string(),
};
let response = client
.post(&format!("{}/auth/account/forgot-password", base_url))
.header("Content-Type", "application/json")
.json(&forgot_password_request)
.send()
.await?;
let result = response.json::<Value>().await?;
println!("Password reset requested: {:?}", result);
Ok(result)
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
let base_url = "your_base_url"; // Replace with actual base URL
// Request password reset
request_password_reset(&client, base_url, "user@example.com").await?;
Ok(())
}
Response (Always Success for Security):
{
"message": "If an account with this email exists, a password reset email has been sent"
}
Step 2: Create New Password with Token
After receiving the 8-character token via email, users can set their new password.
- cURL
- JavaScript
- Python
- Rust
curl -X POST "$baseUrl/auth/account/create-password-for-forgot-password" \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"token": "12345678",
"password": "new_secure_password123",
"password_confirmation": "new_secure_password123"
}'
const createNewPassword = async (email, token, newPassword) => {
try {
const response = await fetch(`${baseUrl}/auth/account/create-password-for-forgot-password`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: email,
token: token,
password: newPassword,
password_confirmation: newPassword,
}),
});
const data = await response.json();
if (response.ok) {
console.log("Password created successfully:", data);
} else {
console.error("Error creating password:", data);
}
} catch (error) {
console.error("Error creating password:", error);
}
};
// Usage
createNewPassword("user@example.com", "12345678", "new_secure_password123");
import requests
import json
def create_new_password(email, token, new_password):
url = f"{baseUrl}/auth/account/create-password-for-forgot-password"
headers = {
'Content-Type': 'application/json'
}
payload = {
"email": email,
"token": token,
"password": new_password,
"password_confirmation": new_password
}
response = requests.post(url, headers=headers, data=json.dumps(payload))
if response.status_code == 200:
print('Password created successfully:', response.json())
else:
print('Error creating password:', response.text)
# Usage
create_new_password('user@example.com', '12345678', 'new_secure_password123')
use reqwest::Client;
use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Serialize)]
struct CreatePasswordRequest {
email: String,
token: String,
password: String,
password_confirmation: String,
}
async fn create_new_password(
client: &Client,
base_url: &str,
email: &str,
token: &str,
new_password: &str
) -> Result<Value, Box<dyn std::error::Error>> {
let create_password_request = CreatePasswordRequest {
email: email.to_string(),
token: token.to_string(),
password: new_password.to_string(),
password_confirmation: new_password.to_string(),
};
let response = client
.post(&format!("{}/auth/account/create-password-for-forgot-password", base_url))
.header("Content-Type", "application/json")
.json(&create_password_request)
.send()
.await?;
let result = response.json::<Value>().await?;
println!("Password created: {:?}", result);
Ok(result)
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
let base_url = "your_base_url"; // Replace with actual base URL
// Create new password
create_new_password(&client, base_url, "user@example.com", "12345678", "new_secure_password123").await?;
Ok(())
}
Success Response:
{
"message": "Password created successfully"
}
Error Responses
Step 1 - Request Token Errors:
Invalid Email Format (400 Bad Request):
{
"message": [
"email must be an email",
"email should not be empty"
],
"error": "Bad Request",
"statusCode": 400
}
Step 2 - Create Password Errors:
Validation Errors (400 Bad Request):
{
"message": [
"email should not be empty",
"token should not be empty",
"password must be longer than or equal to 8 characters",
"password_confirmation should not be empty"
],
"error": "Bad Request",
"statusCode": 400
}
Invalid or Expired Token (400 Bad Request):
{
"status": 400,
"error": "Invalid or expired reset token"
}
Password Mismatch (400 Bad Request):
{
"status": 400,
"error": "Password and confirmation do not match"
}
Frontend Integration
For frontend applications, here's a typical integration pattern:
// Complete forgot password flow example
class ForgotPasswordService {
constructor(baseUrl) {
this.baseUrl = baseUrl;
}
// Step 1: Request reset token
async requestReset(email) {
try {
const response = await fetch(`${this.baseUrl}/auth/account/forgot-password`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email })
});
return await response.json();
} catch (error) {
throw new Error('Failed to request password reset');
}
}
// Step 2: Create new password
async createPassword(email, token, password, passwordConfirmation) {
try {
const response = await fetch(`${this.baseUrl}/auth/account/create-password-for-forgot-password`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email,
token,
password,
password_confirmation: passwordConfirmation
})
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || 'Failed to create password');
}
return await response.json();
} catch (error) {
throw error;
}
}
}
// Usage example
const forgotPasswordService = new ForgotPasswordService('https://your-api.com');
// Handle forgot password form submission
async function handleForgotPassword(email) {
try {
await forgotPasswordService.requestReset(email);
// Show success message - always success for security
showMessage('If an account exists, a reset email has been sent');
} catch (error) {
showError('An error occurred. Please try again.');
}
}
// Handle password creation form submission
async function handlePasswordCreation(email, token, password, confirmPassword) {
try {
await forgotPasswordService.createPassword(email, token, password, confirmPassword);
showMessage('Password updated successfully! You can now log in.');
redirectToLogin();
} catch (error) {
showError(error.message);
}
}
Token Management
- Generation: Unique 8-character numeric tokens (e.g., "12345678")
- Expiration: 1 hour from generation
- Cleanup: Previous tokens are automatically deleted when new ones are requested
- Usage: Single-use tokens that are deleted after successful password creation
- Security: Tokens cannot be used to authenticate for other endpoints
Account Verification Bonus
When users successfully complete the forgot password flow:
- If their email was previously unverified, it gets automatically verified
- The
email_verified_atfield is set to the current timestamp - This provides a seamless experience for users who forgot their password before verifying their email
Authentication Methods
Authentication with Tokens
To demonstrate authentication using tokens, we will use the example of retrieving the authenticated user's details. This involves sending a GET request to our API, which allows you to verify the authentication status and access the user's information.
- cURL
- JavaScript
- Python
- Rust
curl -X GET "$baseUrl/auth/account/me" \
-H "Authorization: Bearer $token" \
-H "Content-Type: application/json"
const getUserDetails = async (token) => {
try {
const response = await fetch(`${baseUrl}/auth/account/me`, {
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
});
const data = await response.json();
console.log("User details:", data);
} catch (error) {
console.error("Error fetching user details:", error);
}
};
// Usage
const token = "your_auth_token"; // Replace with actual token
getUserDetails(token);
import requests
def get_user_details(token):
url = f"{baseUrl}/auth/account/me"
headers = {
'Authorization': f"Bearer {token}",
'Content-Type': 'application/json'
}
response = requests.get(url, headers=headers)
if response.status_code == 200:
print('User details:', response.json())
else:
print('Error fetching user details:', response.text)
# Usage
token = 'your_auth_token' # Replace with actual token
get_user_details(token)
use reqwest::Client;
use serde_json::Value;
async fn get_user_details(client: &Client, base_url: &str, token: &str)
-> Result<Value, Box<dyn std::error::Error>> {
let response = client
.get(&format!("{}/auth/account/me", base_url))
.header("Authorization", format!("Bearer {}", token))
.header("Content-Type", "application/json")
.send()
.await?;
let user_data = response.json::<Value>().await?;
println!("User details: {:?}", user_data);
Ok(user_data)
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
// Get user details
let token = "your_auth_token"; // Replace with actual token
let user_data = get_user_details(&client, baseUrl, token).await?;
Ok(())
}
Upon successful authentication, the API will respond with the user's account details:
{
"data": {
"id": 1,
"name": "First Account",
"email": "first@email.com",
"api_key_generated_at": "2025-03-06T02:04:10.580Z",
"created_at": "2025-03-06T00:44:11.292Z",
"updated_at": "2025-03-06T02:04:10.581Z"
},
"message": "authentication data"
}
Authentication with API Keys
To demonstrate authentication using API keys, you can use the API keys in one of two ways:
- Using the
base64_encodedvalue directly:
Authorization: Basic ams4c2E3ZGZnOThzN2RmOThnN3NkZmc4Nzo4c2Q3Zmc4c2Q3Zmc4c2Q3Zjk4Z3M3ZGY5OGc=
- Using the
api_keyas username andapi_secretas password for Basic Auth.
- cURL
- JavaScript
- Python
- Rust
# Using base64_encoded value
curl -X GET "$baseUrl/auth/account/me" \
-H "Authorization: Basic ams4c2E3ZGZnOThzN2RmOThnN3NkZmc4Nzo4c2Q3Zmc4c2Q3Zmc4c2Q3Zjk4Z3M3ZGY5OGc=" \
-H "Content-Type: application/json"
# Using api_key and api_secret for Basic Auth
curl -X GET "$baseUrl/auth/account/me" \
-u "jk8sa7dfg98s7df98g7sdfg87:8sd7fg8sd7fg8sd7f98gs7df98g" \
-H "Content-Type: application/json"
const getUserDetailsWithApiKey = async (apiKey, apiSecret) => {
try {
// Using base64_encoded value
const response1 = await fetch(`${baseUrl}/auth/account/me`, {
method: "GET",
headers: {
Authorization:
"Basic ams4c2E3ZGZnOThzN2RmOThnN3NkZmc4Nzo4c2Q3Zmc4c2Q3Zmc4c2Q3Zjk4Z3M3ZGY5OGc=",
"Content-Type": "application/json",
},
});
const data1 = await response1.json();
console.log("User details with base64_encoded:", data1);
// Using api_key and api_secret for Basic Auth
const response2 = await fetch(`${baseUrl}/auth/account/me`, {
method: "GET",
headers: {
Authorization: `Basic ${btoa(`${apiKey}:${apiSecret}`)}`,
"Content-Type": "application/json",
},
});
const data2 = await response2.json();
console.log("User details with api_key and api_secret:", data2);
} catch (error) {
console.error("Error fetching user details:", error);
}
};
// Usage
const apiKey = "jk8sa7dfg98s7df98g7sdfg87"; // Replace with actual API key
const apiSecret = "8sd7fg8sd7fg8sd7f98gs7df98g"; // Replace with actual API secret
getUserDetailsWithApiKey(apiKey, apiSecret);
import requests
from requests.auth import HTTPBasicAuth
def get_user_details_with_api_key():
url = f"{baseUrl}/auth/account/me"
# Using base64_encoded value
headers1 = {
'Authorization': 'Basic ams4c2E3ZGZnOThzN2RmOThnN3NkZmc4Nzo4c2Q3Zmc4c2Q3Zmc4c2Q3Zjk4Z3M3ZGY5OGc=',
'Content-Type': 'application/json'
}
response1 = requests.get(url, headers=headers1)
if response1.status_code == 200:
print('User details with base64_encoded:', response1.json())
else:
print('Error fetching user details with base64_encoded:', response1.text)
# Using api_key and api_secret for Basic Auth
response2 = requests.get(url, auth=HTTPBasicAuth('jk8sa7dfg98s7df98g7sdfg87', '8sd7fg8sd7fg8sd7f98gs7df98g'))
if response2.status_code == 200:
print('User details with api_key and api_secret:', response2.json())
else:
print('Error fetching user details with api_key and api_secret:', response2.text)
# Usage
get_user_details_with_api_key()
use reqwest::Client;
use serde_json::Value;
async fn get_user_details_with_api_key(client: &Client, base_url: &str)
-> Result<(), Box<dyn std::error::Error>> {
// Using base64_encoded value
let response1 = client
.get(&format!("{}/auth/account/me", base_url))
.header("Authorization", "Basic ams4c2E3ZGZnOThzN2RmOThnN3NkZmc4Nzo4c2Q3Zmc4c2Q3Zmc4c2Q3Zjk4Z3M3ZGY5OGc=")
.header("Content-Type", "application/json")
.send()
.await?;
let user_data1 = response1.json::<Value>().await?;
println!("User details with base64_encoded: {:?}", user_data1);
// Using api_key and api_secret for Basic Auth
let response2 = client
.get(&format!("{}/auth/account/me", base_url))
.basic_auth("jk8sa7dfg98s7df98g7sdfg87", Some("8sd7fg8sd7fg8sd7f98gs7df98g"))
.header("Content-Type", "application/json")
.send()
.await?;
let user_data2 = response2.json::<Value>().await?;
println!("User details with api_key and api_secret: {:?}", user_data2);
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
// Get user details
get_user_details_with_api_key(&client, baseUrl).await?;
Ok(())
}
Upon successful authentication, the API will respond with the user's account details:
{
"data": {
"id": 1,
"name": "First Account",
"email": "first@email.com",
"api_key_generated_at": "2025-03-06T02:04:10.580Z",
"created_at": "2025-03-06T00:44:11.292Z",
"updated_at": "2025-03-06T02:04:10.581Z"
},
"message": "authentication data"
}