Service Integration Guide

Complete implementation guide for integrating your RegardingWork service with Hub authentication

Configured Services: ✅ All Ready for Integration

All RegardingWork services have CORS and SSO domain permissions configured and ready to use

Services Active:
Game • Premium • Display • CE • Family • Desk

🔧 Configured RegardingWork Services

The following services are pre-configured and ready for Hub authentication integration:

  • game.regardingwork.com - Game Platform
  • premium.regardingwork.com - Premium Music Service
  • display.regardingwork.com - Display Service
  • ce.regardingwork.com - CE Application
  • family.regardingwork.com - Family Service
  • desk.regardingwork.com - Desk Service
Need a new service added? Contact the Hub team to add your domain to the CORS and SSO configuration.

📋 Complete Implementation Example

Real-world integration guide using Family Service

1. Create Authentication Service

Create a centralized authentication service for your app:

class RegardingWorkAuth {
    constructor() {
        this.hubBaseUrl = 'https://hub.regardingwork.com/api';
        this.currentUser = null;
    }

    async initialize() {
        // Check for existing session on app start
        const user = await this.validateSession();
        if (user) {
            this.currentUser = user;
            return true;
        }
        return false;
    }

    async login(username, password) {
        try {
            const response = await fetch(`${this.hubBaseUrl}/auth/login`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                    username: username,
                    password: password
                })
            });

            if (response.ok) {
                const data = await response.json();
                
                // Store tokens securely
                localStorage.setItem('access_token', data.access_token);
                localStorage.setItem('refresh_token', data.refresh_token);
                
                this.currentUser = data.user;
                
                return {
                    success: true,
                    user: data.user,
                    tokens: {
                        access: data.access_token,
                        refresh: data.refresh_token
                    }
                };
            } else {
                const error = await response.json();
                throw new Error(error.error || 'Authentication failed');
            }
        } catch (error) {
            console.error('Hub authentication failed:', error);
            return {
                success: false,
                error: error.message
            };
        }
    }

    async validateSession() {
        const token = localStorage.getItem('access_token');
        if (!token) return false;

        try {
            const response = await fetch(`${this.hubBaseUrl}/auth/validate`, {
                method: 'GET',
                headers: {
                    'Authorization': `Bearer ${token}`
                }
            });

            if (response.ok) {
                const data = await response.json();
                return data.user; // User is authenticated
            } else {
                // Token invalid or expired - try refresh
                return await this.refreshToken();
            }
        } catch (error) {
            console.error('Token validation failed:', error);
            return false;
        }
    }

    async refreshToken() {
        const refreshToken = localStorage.getItem('refresh_token');
        if (!refreshToken) return false;

        try {
            const response = await fetch(`${this.hubBaseUrl}/auth/refresh`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                    refresh_token: refreshToken
                })
            });

            if (response.ok) {
                const data = await response.json();
                
                // Update stored token
                localStorage.setItem('access_token', data.access_token);
                
                return data.user;
            } else {
                // Refresh failed - user needs to login again
                this.clearTokens();
                return false;
            }
        } catch (error) {
            console.error('Token refresh failed:', error);
            return false;
        }
    }

    async logout() {
        const token = localStorage.getItem('access_token');
        const refreshToken = localStorage.getItem('refresh_token');

        try {
            // Revoke tokens on server
            await fetch(`${this.hubBaseUrl}/auth/logout`, {
                method: 'POST',
                headers: {
                    'Authorization': `Bearer ${token}`,
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                    refresh_token: refreshToken
                })
            });
        } catch (error) {
            console.warn('Server logout failed, clearing local tokens anyway');
        }

        this.clearTokens();
        this.currentUser = null;
    }

    clearTokens() {
        localStorage.removeItem('access_token');
        localStorage.removeItem('refresh_token');
    }

    isAuthenticated() {
        return this.currentUser !== null;
    }

    getUser() {
        return this.currentUser;
    }

    getAuthHeaders() {
        const token = localStorage.getItem('access_token');
        return token ? { 'Authorization': `Bearer ${token}` } : {};
    }
}

2. Implementation Usage

How to use the authentication service in your app:

// Initialize authentication on app start
const auth = new RegardingWorkAuth();

// Check for existing session
auth.initialize().then(loggedIn => {
    if (loggedIn) {
        console.log('User already authenticated:', auth.getUser());
        showDashboard();
    } else {
        showLoginForm();
    }
});

// Handle login form submission
async function handleLogin(username, password) {
    const result = await auth.login(username, password);
    
    if (result.success) {
        console.log('Login successful:', result.user);
        showDashboard();
    } else {
        console.error('Login failed:', result.error);
        showError(result.error);
    }
}

// Handle logout
async function handleLogout() {
    await auth.logout();
    showLoginForm();
}

// Making authenticated API calls to your service
async function makeAuthenticatedRequest(url, options = {}) {
    const authHeaders = auth.getAuthHeaders();
    
    const response = await fetch(url, {
        ...options,
        headers: {
            ...options.headers,
            ...authHeaders
        }
    });
    
    if (response.status === 401) {
        // Token might be expired, try refreshing
        const refreshed = await auth.refreshToken();
        if (refreshed) {
            // Retry with new token
            return makeAuthenticatedRequest(url, options);
        } else {
            // Refresh failed, redirect to login
            auth.clearTokens();
            showLoginForm();
            return null;
        }
    }
    
    return response;
}

3. Login Form HTML

Simple login form for your service:

<!-- Login Form -->
<div id="loginForm" class="login-container">
    <div class="card">
        <div class="card-header">
            <h3>Login to RegardingWork Family</h3>
        </div>
        <div class="card-body">
            <form id="authForm">
                <div class="mb-3">
                    <label for="username" class="form-label">Username</label>
                    <input type="text" class="form-control" id="username" required>
                </div>
                <div class="mb-3">
                    <label for="password" class="form-label">Password</label>
                    <input type="password" class="form-control" id="password" required>
                </div>
                <button type="submit" class="btn btn-primary w-100">
                    Login with RegardingWork Hub
                </button>
            </form>
            <div id="errorMessage" class="alert alert-danger mt-3 d-none"></div>
        </div>
    </div>
</div>

<!-- Dashboard (shown after login) -->
<div id="dashboard" class="d-none">
    <nav class="navbar navbar-expand-lg navbar-dark bg-primary">
        <div class="container">
            <span class="navbar-brand">RegardingWork Family</span>
            <div class="navbar-nav ms-auto">
                <span id="userInfo" class="navbar-text me-3"></span>
                <button class="btn btn-outline-light" onclick="handleLogout()">Logout</button>
            </div>
        </div>
    </nav>
    
    <div class="container mt-4">
        <h1>Welcome to RegardingWork Family!</h1>
        <p>You are now authenticated with RegardingWork Hub.</p>
    </div>
</div>

<script>
// Form handling
document.getElementById('authForm').addEventListener('submit', async function(e) {
    e.preventDefault();
    
    const username = document.getElementById('username').value;
    const password = document.getElementById('password').value;
    const errorDiv = document.getElementById('errorMessage');
    
    errorDiv.classList.add('d-none');
    
    const result = await auth.login(username, password);
    
    if (result.success) {
        showDashboard();
    } else {
        errorDiv.textContent = result.error;
        errorDiv.classList.remove('d-none');
    }
});

function showLoginForm() {
    document.getElementById('loginForm').classList.remove('d-none');
    document.getElementById('dashboard').classList.add('d-none');
}

function showDashboard() {
    document.getElementById('loginForm').classList.add('d-none');
    document.getElementById('dashboard').classList.remove('d-none');
    
    const user = auth.getUser();
    document.getElementById('userInfo').textContent = `Hello, ${user.username}!`;
}

function showError(message) {
    const errorDiv = document.getElementById('errorMessage');
    errorDiv.textContent = message;
    errorDiv.classList.remove('d-none');
}
</script>

Security Best Practices

✅ Do:
  • Store tokens in secure storage (localStorage for web, keychain for native)
  • Implement automatic token refresh before expiration
  • Clear tokens completely on logout
  • Handle 401 responses with token refresh attempts
  • Use HTTPS for all API calls
  • Validate user sessions on app startup
❌ Don't:
  • Log tokens to console or error messages
  • Store tokens in unsecured locations
  • Ignore token expiration handling
  • Make requests without error handling
  • Store passwords or sensitive data
  • Skip server-side token revocation on logout

📊 Expected API Responses

Successful Login Response:
{
  "message": "Login successful",
  "user": {
    "id": 19,
    "username": "familyuser",
    "email": "user@family.com",
    "role": "USER",
    "premium_tier": "FREE",
    "is_active": true,
    "created_at": "2025-08-21T14:53:11.449505",
    "email_verified": true
  },
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
  "refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
}
Authentication Error Response:
{
  "error": "Invalid credentials"
}
Token Validation Response:
{
  "valid": true,
  "user": {
    "id": 19,
    "username": "familyuser",
    "role": "USER"
  }
}

Testing Your Integration

Test Credentials:
Username: janechen
Password: jane123
Integration Checklist:
  • Login form submits to Hub API correctly
  • Tokens are stored securely after login
  • User info displays correctly after authentication
  • Token validation works on page refresh
  • Automatic token refresh handles expired tokens
  • Logout clears tokens and redirects to login
  • Error handling shows user-friendly messages
  • CORS requests work without errors

Common Issues & Solutions

Problem: Browser blocks requests with CORS errors.
Solution: Your domain should already be configured. If you get CORS errors, contact the Hub team to add your domain.
Check: Ensure you're using the exact domain name (e.g., https://family.regardingwork.com)

Problem: API returns 401 when making authenticated requests.
Solutions:
  • Check token is included in Authorization header: Bearer {token}
  • Try refreshing the token if it's expired
  • Clear tokens and re-authenticate if refresh fails
  • Verify credentials are correct

Problem: Requests fail with "Failed to fetch" or similar.
Solutions:
  • Check Hub service status at hub.regardingwork.com
  • Implement retry logic with exponential backoff
  • Check browser network tab for detailed error information
  • Verify you're using HTTPS URLs
Need Help?

If you encounter issues not covered in this guide: