๐ฏ Comprehensive Integration Guide
This guide provides detailed instructions for integrating with the Escore Auth Service at https://auth.escore.live.
๐ Contents
๐ค User Profile Structure
All user objects returned by the API include the following profile fields:
{
"id": 1,
"name": "John",
"surname": "Doe",
"email": "john@example.com",
"is_child_user": false,
"can_login": true,
"birth_year": 1990, // nullable integer
"birth_date": "1990-05-15", // nullable date (YYYY-MM-DD)
"gender": "male", // nullable string
"country_code": "US", // nullable string (ISO 3166-1 alpha-2)
"created_at": "2025-06-10T17:30:00.000000Z",
"updated_at": "2025-06-10T17:30:00.000000Z"
}
๐ Profile Field Details
- surname: String (max 255 chars, last name/family name)
- birth_year: Integer (1900-current year)
- birth_date: Date string (YYYY-MM-DD, before today)
- gender: String (max 20 chars, e.g., "male", "female", "other")
- country_code: 2-letter ISO country code (e.g., "US", "CA", "GB")
โ Important Notes
- All profile fields are optional and can be
null - Fields can be provided during registration
- Child users can have profile fields
- Profile data is included in all user responses
- surname is separate from name (first name)
๐ Frontend Integration
Complete JavaScript Authentication Class
class EscoreAuth {
constructor(baseUrl = 'https://auth.escore.live') {
this.baseUrl = baseUrl;
this.token = localStorage.getItem('auth_token');
}
async register(userData) {
const response = await fetch(`${this.baseUrl}/api/register`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name: userData.name,
surname: userData.surname,
email: userData.email,
password: userData.password,
password_confirmation: userData.password,
birth_year: userData.birth_year,
birth_date: userData.birth_date,
gender: userData.gender,
country_code: userData.country_code
})
});
const result = await response.json();
if (response.ok) {
this.token = result.access_token;
localStorage.setItem('auth_token', this.token);
return { success: true, user: result.user };
}
return { success: false, message: result.message };
}
async login(email, password) {
const response = await fetch(`${this.baseUrl}/api/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password })
});
const result = await response.json();
if (response.ok) {
this.token = result.access_token;
localStorage.setItem('auth_token', this.token);
return { success: true, user: result.user };
}
return { success: false, message: result.message };
}
async logout() {
if (!this.token) return;
await fetch(`${this.baseUrl}/api/logout`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${this.token}` }
});
localStorage.removeItem('auth_token');
this.token = null;
}
async makeAuthenticatedRequest(endpoint, options = {}) {
if (!this.token) throw new Error('No token available');
const response = await fetch(`${this.baseUrl}${endpoint}`, {
...options,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.token}`,
...options.headers
}
});
if (response.status === 401) {
localStorage.removeItem('auth_token');
this.token = null;
window.location.href = '/login';
return;
}
return { success: response.ok, data: await response.json() };
}
// Child User Methods
async createChildUser(childData) {
return this.makeAuthenticatedRequest('/api/children', {
method: 'POST',
body: JSON.stringify({
name: childData.name,
surname: childData.surname,
birth_year: childData.birth_year,
birth_date: childData.birth_date,
gender: childData.gender,
country_code: childData.country_code
})
});
}
async assignEmailToChild(childId, email, password) {
return this.makeAuthenticatedRequest(`/api/children/${childId}/assign-email`, {
method: 'PUT',
body: JSON.stringify({
email,
password,
password_confirmation: password
})
});
}
async getChildUsers() {
return this.makeAuthenticatedRequest('/api/children');
}
}
// Usage Example
const auth = new EscoreAuth();
// Register with profile fields
const result = await auth.register({
name: 'John',
surname: 'Doe',
email: 'john@example.com',
password: 'password123',
birth_year: 1990,
birth_date: '1990-05-15',
gender: 'male',
country_code: 'US'
});
if (result.success) {
console.log('Registered:', result.user);
// User object now includes: surname, birth_year, birth_date, gender, country_code
}
React Hook Integration
import { useState, useEffect, createContext, useContext } from 'react';
const AuthContext = createContext();
export const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const auth = new EscoreAuth();
useEffect(() => {
const token = localStorage.getItem('auth_token');
if (token) {
auth.token = token;
auth.makeAuthenticatedRequest('/api/user').then(result => {
if (result.success) setUser(result.data.user);
setLoading(false);
});
} else {
setLoading(false);
}
}, []);
const login = async (email, password) => {
const result = await auth.login(email, password);
if (result.success) setUser(result.user);
return result;
};
const logout = async () => {
await auth.logout();
setUser(null);
};
return (
<AuthContext.Provider value=\{\{ user, login, logout, loading, auth \}\}>
\{children\}
</AuthContext.Provider>
);
};
export const useAuth = () => useContext(AuthContext);
๐ฅ๏ธ Backend Integration
Node.js/Express Example
const express = require('express');
const axios = require('axios');
const app = express();
const AUTH_SERVICE = 'https://auth.escore.live';
const validateToken = async (req, res, next) => {
const authHeader = req.headers.authorization;
if (!authHeader?.startsWith('Bearer ')) {
return res.status(401).json({ message: 'No token provided' });
}
const token = authHeader.substring(7);
try {
const response = await axios.get(`${AUTH_SERVICE}/api/verify`, {
headers: { 'Authorization': `Bearer ${token}` }
});
req.user = response.data.user;
next();
} catch (error) {
return res.status(401).json({ message: 'Invalid token' });
}
};
// Protected route
app.get('/api/protected', validateToken, (req, res) => {
res.json({ message: 'Access granted', user: req.user });
});
app.listen(3000);
PHP/Laravel Example
<?php
namespace App\Services;
use Illuminate\Support\Facades\Http;
class EscoreAuthService
{
private $baseUrl = 'https://auth.escore.live/api';
public function validateToken(string $token): ?array
{
try {
$response = Http::withHeaders([
'Authorization' => "Bearer $token"
])->get($this->baseUrl . '/verify');
return $response->successful() ? $response->json('user') : null;
} catch (\Exception $e) {
return null;
}
}
public function getUserById(int $userId): ?array
{
try {
$response = Http::get($this->baseUrl . "/public/user/$userId");
return $response->successful() ? $response->json('user') : null;
} catch (\Exception $e) {
return null;
}
}
}
// Middleware
namespace App\Http\Middleware;
class EscoreAuth
{
public function handle($request, $next)
{
$token = $request->bearerToken();
if (!$token) {
return response()->json(['message' => 'No token provided'], 401);
}
$authService = new \App\Services\EscoreAuthService();
$user = $authService->validateToken($token);
if (!$user) {
return response()->json(['message' => 'Invalid token'], 401);
}
$request->merge(['auth_user' => $user]);
return $next($request);
}
}
๐ถ Child User Management
Complete Child User Workflow
class ChildUserManager {
constructor(auth) {
this.auth = auth;
}
async createChild(childData) {
const result = await this.auth.createChildUser(childData);
if (result.success) {
console.log('Child created (no login yet):', result.data.child);
return result.data.child;
}
throw new Error(result.data.message);
}
async assignEmailToChild(childId, email, password) {
const result = await this.auth.assignEmailToChild(childId, email, password);
if (result.success) {
console.log('Email assigned, child can now login');
return result.data.child;
}
throw new Error(result.data.message);
}
async getChildren() {
const result = await this.auth.getChildUsers();
return result.success ? result.data.children : [];
}
}
// Usage Example
const manager = new ChildUserManager(auth);
// 1. Create child with profile (cannot login)
const child = await manager.createChild({
name: 'Emma',
surname: 'Doe',
birth_year: 2010,
birth_date: '2010-08-20',
gender: 'female',
country_code: 'US'
});
// 2. Later, assign email (can now login)
await manager.assignEmailToChild(child.id, 'emma@family.com', 'emma123');
// 3. Child can now login independently
const childAuth = new EscoreAuth();
const childLogin = await childAuth.login('emma@family.com', 'emma123');
// 4. All user objects include profile fields
console.log('Child profile:', childLogin.user);
// Output includes: surname, birth_year, birth_date, gender, country_code
๐งช Testing Examples
cURL Commands
# Health Check
curl https://auth.escore.live/api/health
# Register User with Profile
curl -X POST https://auth.escore.live/api/register \
-H "Content-Type: application/json" \
-d '{
"name": "Test",
"surname": "User",
"email": "test@example.com",
"password": "password123",
"password_confirmation": "password123",
"birth_year": 1990,
"birth_date": "1990-05-15",
"gender": "male",
"country_code": "US"
}'
# Login
curl -X POST https://auth.escore.live/api/login \
-H "Content-Type: application/json" \
-d '{
"email": "test@example.com",
"password": "password123"
}'
# Get User (replace TOKEN)
curl https://auth.escore.live/api/user \
-H "Authorization: Bearer TOKEN"
# Create Child User with Profile
curl -X POST https://auth.escore.live/api/children \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Emma",
"surname": "Doe",
"birth_year": 2010,
"birth_date": "2010-08-20",
"gender": "female",
"country_code": "US"
}'
JavaScript Testing
// Test authentication flow
async function testAuth() {
const auth = new EscoreAuth();
try {
// Register with profile
const register = await auth.register({
name: 'Test',
surname: 'User',
email: `test${Date.now()}@example.com`,
password: 'password123',
birth_year: 1990,
birth_date: '1990-05-15',
gender: 'male',
country_code: 'US'
});
console.log('Registration:', register);
// Create child with profile
const child = await auth.createChildUser({
name: 'Test',
surname: 'Child',
birth_year: 2010,
birth_date: '2010-08-20',
gender: 'female',
country_code: 'US'
});
console.log('Child created:', child);
// Assign email to child
const childEmail = await auth.assignEmailToChild(
child.data.child.id,
`child${Date.now()}@example.com`,
'childpass123'
);
console.log('Child email assigned:', childEmail);
} catch (error) {
console.error('Test failed:', error);
}
}
testAuth();
โญ Best Practices
๐ Security Best Practices
- Always use HTTPS in production
- Store tokens securely (httpOnly cookies preferred)
- Implement token refresh logic
- Validate tokens server-side for sensitive operations
- Handle authentication errors gracefully
- Use CSRF protection for web applications
๐ Performance Tips
- Cache user data when appropriate
- Use connection pooling for backend services
- Implement request retries with exponential backoff
- Handle rate limiting gracefully
- Monitor authentication metrics
- Minimize token payload size
๐ ๏ธ Error Handling
- Always handle network failures
- Provide meaningful error messages
- Log authentication failures for monitoring
- Implement graceful degradation
- Use proper HTTP status codes
- Handle token expiration automatically
๐ Production Deployment Checklist
- โ Test all authentication flows
- โ Verify CORS configuration for your domains
- โ Set up monitoring and alerting
- โ Configure rate limiting
- โ Test child user workflows
- โ Implement proper error handling
- โ Set up backup authentication methods
- โ Document your integration for your team
๐ Additional Resources
Check out the main API documentation for detailed endpoint specifications.