📚 Complete guide

🎫 External Company Integration Guide

Seamless Authentication & Ticket System Integration

Version: 1.0
Last Updated: October 27, 2025
Support: support@flare99.com


📋 Table of Contents

  1. Overview
  2. Integration Methods
  3. Prerequisites
  4. Step-by-Step Implementation
  5. Code Examples
  6. Security Considerations
  7. Testing & Validation
  8. Troubleshooting
  9. API Reference

🎯 Overview

This guide enables external companies to integrate their websites with our centralized ticket system (tickets.flare99.com). Users from your platform can seamlessly submit support tickets without re-authenticating.

Key Features

Single Sign-On (SSO) - Users authenticate once on your platform
Automatic User Sync - User data automatically syncs to ticket system
Cross-Domain Authentication - Secure authentication across different domains
No Password Required - Users don't need separate credentials
Session Persistence - Maintains user session across platforms


🔧 Integration Methods

We offer three integration approaches based on your needs:

Method 1: Form-Based POST Integration (Recommended)

  • ✅ Simple to implement
  • ✅ Works without CORS configuration
  • ✅ Requires minimal JavaScript
  • ✅ Best for basic integrations

Method 2: AJAX/Fetch API Integration

  • ✅ Modern approach
  • ✅ Better user experience (no page reload)
  • ✅ Requires CORS configuration
  • ✅ Best for SPAs and modern web apps

Method 3: localStorage + postMessage Integration

  • ✅ Advanced cross-domain communication
  • ✅ Handles complex scenarios
  • ✅ Requires both domains to cooperate
  • ✅ Best for embedded widgets

📋 Prerequisites

1. Company Registration

Contact us to register your company and receive:

  • Tenant Slug: Your unique identifier (e.g., yourcompany)
  • API Endpoint: Redirect API Route
  • Subdomain: https://ticket.yourcompany.com (optional custom domain)

2. Technical Requirements

  • HTTPS-enabled website (required for security)
  • User authentication system (to identify logged-in users)
  • Ability to modify frontend code (JavaScript/HTML)

3. User Data Required

For each authenticated user, you need:

  • Email Address (required)
  • Full Name (required)
  • Redirect URL (optional - where to send user after authentication)

🚀 Step-by-Step Implementation

Step 1: Expose User Data to JavaScript

Add this code to your main layout file (footer, header, or before </body>):

<script>
    // Expose authenticated user data to JavaScript
    window.authUser = {
        email: '{{ $authUser?->email }}',
        name: '{{ $authUser?->name }}',
        // Add any additional fields you want to pass
    };

    // Store in localStorage for persistence (optional)
    if (window.authUser && window.authUser.email) {
        localStorage.setItem('yourcompany_user_email', window.authUser.email);
        localStorage.setItem('yourcompany_user_name', window.authUser.name || '');
    }
</script>

For Different Frameworks:

Laravel (Blade)

<script>
    window.authUser = @json([
        'email' => Auth::user()?->email,
        'name' => Auth::user()?->name,
    ]);
</script>

WordPress

<script>
    window.authUser = <?php echo json_encode([
        'email' => wp_get_current_user()->user_email,
        'name' => wp_get_current_user()->display_name,
    ]); ?>;
</script>

React/Next.js

// Set in context or state
const [authUser, setAuthUser] = useState({
    email: session?.user?.email,
    name: session?.user?.name,
});

// Make available globally
useEffect(() => {
    window.authUser = authUser;
}, [authUser]);

Step 2: Create the Contact Support Function

Add this JavaScript function to handle ticket creation:

/**
 * Redirects user to ticket system with authentication
 * @param {Event} e - Click event (optional)
 * @param {boolean} openInNewTab - Whether to open in new tab (default: true)
 */
function contactSupport(e, openInNewTab = true) {
    if (e) e.preventDefault();

    const user = window.authUser;

    // Check if user is logged in
    if (!user || !user.email) {
        // Redirect to login page
        alert('Please sign in to submit a support ticket.');
        window.location = '/login'; // Adjust to your login URL
        return;
    }

    // Create form for POST request
    const form = document.createElement('form');
    form.method = 'POST';
    form.action = 'https://tickets.flare99.com/api/auth/redirect/yourcompany'; // Replace 'yourcompany'
    form.acceptCharset = 'UTF-8';

    // Open in new tab (preserves current page)
    if (openInNewTab) {
        form.target = '_blank';
    }

    // Add user data as hidden fields
    const fields = {
        email: user.email,
        name: user.name || '',
        redirect_url: 'https://ticket.yourcompany.com/dashboard' // Optional
    };

    for (const [name, value] of Object.entries(fields)) {
        const input = document.createElement('input');
        input.type = 'hidden';
        input.name = name;
        input.value = value;
        form.appendChild(input);
    }

    // Submit form
    document.body.appendChild(form);
    form.submit();
    form.remove();
}

Step 3: Add Submit Ticket Button/Link

Add a clickable element that triggers the function:

<!-- Simple Link -->
<a href="#" onclick="contactSupport(event)">
    Submit Support Ticket
</a>

<!-- Button with Icon -->
<button onclick="contactSupport(event)" class="btn btn-primary">
    <i class="icon-ticket"></i> Submit Ticket
</button>

<!-- Navigation Menu Item -->
<li class="nav-item">
    <a href="#" onclick="contactSupport(event)" class="nav-link">
        Support
    </a>
</li>

Step 4: CORS Configuration (For AJAX Integration)

If using AJAX/Fetch instead of form POST, request CORS configuration from us. We'll add your domain to our allowlist:

// This is configured on our end - no action needed from you
'allowed_origins' => [
    'https://yourcompany.com',
    'https://ticket.yourcompany.com',
],

💻 Code Examples

Example 1: Basic Form Integration (Laravel)

File: resources/views/partials/footer.blade.php

<footer>
    <!-- Your footer content -->
    
    <script>
        // Expose user data
        window.authUser = @json([
            'email' => Auth::user()?->email,
            'name' => Auth::user()?->name,
        ]);

        // Store in localStorage
        if (window.authUser && window.authUser.email) {
            localStorage.setItem('yourcompany_user_email', window.authUser.email);
            localStorage.setItem('yourcompany_user_name', window.authUser.name || '');
        }

        // Contact support function
        function contactSupport(e, openInNewTab = true) {
            if (e) e.preventDefault();

            const user = window.authUser;

            if (!user || !user.email) {
                @if (Route::has('login'))
                    window.location = "{{ route('login') }}";
                @else
                    alert('You need to be signed in to contact support.');
                @endif
                return;
            }

            const form = document.createElement('form');
            form.method = 'POST';
            form.action = 'https://tickets.flare99.com/api/auth/redirect/yourcompany';
            form.acceptCharset = 'UTF-8';

            if (openInNewTab) form.target = '_blank';

            const fields = {
                email: user.email,
                name: user.name ?? ''
            };

            for (const [name, value] of Object.entries(fields)) {
                const input = document.createElement('input');
                input.type = 'hidden';
                input.name = name;
                input.value = value;
                form.appendChild(input);
            }

            document.body.appendChild(form);
            form.submit();
            form.remove();
        }
    </script>
</footer>

Example 2: AJAX Integration (Modern JavaScript)

async function contactSupportAjax() {
    const user = window.authUser;

    if (!user || !user.email) {
        alert('Please sign in to submit a support ticket.');
        window.location = '/login';
        return;
    }

    try {
        const response = await fetch('https://tickets.flare99.com/api/auth/redirect/yourcompany', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Accept': 'application/json',
            },
            credentials: 'include', // Important for cookies
            body: JSON.stringify({
                email: user.email,
                name: user.name || '',
                redirect_url: 'https://ticket.yourcompany.com/dashboard'
            })
        });

        if (response.redirected) {
            // Open redirect URL in new tab
            window.open(response.url, '_blank');
        } else {
            const data = await response.json();
            console.log('Response:', data);
        }
    } catch (error) {
        console.error('Error:', error);
        alert('Failed to connect to support system. Please try again.');
    }
}

Example 3: WordPress Integration

File: footer.php

<footer>
    <!-- Footer content -->
    
    <script>
        <?php if (is_user_logged_in()): ?>
            window.authUser = {
                email: '<?php echo esc_js(wp_get_current_user()->user_email); ?>',
                name: '<?php echo esc_js(wp_get_current_user()->display_name); ?>'
            };

            if (window.authUser && window.authUser.email) {
                localStorage.setItem('yourcompany_user_email', window.authUser.email);
                localStorage.setItem('yourcompany_user_name', window.authUser.name || '');
            }
        <?php else: ?>
            window.authUser = null;
        <?php endif; ?>

        function contactSupport(e, openInNewTab = true) {
            if (e) e.preventDefault();

            const user = window.authUser;

            if (!user || !user.email) {
                alert('Please sign in to submit a support ticket.');
                window.location = '<?php echo wp_login_url(); ?>';
                return;
            }

            const form = document.createElement('form');
            form.method = 'POST';
            form.action = 'https://tickets.flare99.com/api/auth/redirect/yourcompany';
            form.acceptCharset = 'UTF-8';

            if (openInNewTab) form.target = '_blank';

            const fields = {
                email: user.email,
                name: user.name || ''
            };

            for (const [name, value] of Object.entries(fields)) {
                const input = document.createElement('input');
                input.type = 'hidden';
                input.name = name;
                input.value = value;
                form.appendChild(input);
            }

            document.body.appendChild(form);
            form.submit();
            form.remove();
        }
    </script>
</footer>

Example 4: React Component

import React, { useEffect, useState } from 'react';

const SupportButton = ({ user }) => {
    useEffect(() => {
        // Expose user to global scope
        window.authUser = user;
        
        if (user?.email) {
            localStorage.setItem('yourcompany_user_email', user.email);
            localStorage.setItem('yourcompany_user_name', user.name || '');
        }
    }, [user]);

    const contactSupport = (e) => {
        e.preventDefault();

        if (!user || !user.email) {
            alert('Please sign in to submit a support ticket.');
            window.location = '/login';
            return;
        }

        const form = document.createElement('form');
        form.method = 'POST';
        form.action = 'https://tickets.flare99.com/api/auth/redirect/yourcompany';
        form.acceptCharset = 'UTF-8';
        form.target = '_blank';

        const fields = {
            email: user.email,
            name: user.name || ''
        };

        Object.entries(fields).forEach(([name, value]) => {
            const input = document.createElement('input');
            input.type = 'hidden';
            input.name = name;
            input.value = value;
            form.appendChild(input);
        });

        document.body.appendChild(form);
        form.submit();
        form.remove();
    };

    return (
        <button 
            onClick={contactSupport}
            className="btn btn-primary"
        >
            Submit Support Ticket
        </button>
    );
};

export default SupportButton;

🔒 Security Considerations

1. HTTPS Only

  • ✅ Both your website and our ticket system use HTTPS
  • ✅ Cookies are marked as Secure and HttpOnly
  • ✅ Data transmission is encrypted

2. Token-Based Authentication

  • ✅ Short-lived tokens (2-minute expiry)
  • ✅ One-time use tokens (replay protection)
  • ✅ Encrypted token payload (AES-256)
  • ✅ Domain validation (tokens bound to tenant)

3. CORS Protection

  • ✅ Whitelist-based CORS policy
  • ✅ Credentials support only for approved domains
  • ✅ Preflight request validation

4. Session Management

  • ✅ Separate sessions per domain
  • ✅ Session cookies with SameSite=None; Secure
  • ✅ Session regeneration on authentication
  • ✅ Automatic session cleanup

5. Data Validation

  • ✅ Email format validation
  • ✅ Required field checking
  • ✅ SQL injection protection (parameterized queries)
  • ✅ XSS protection (escaped output)

✅ Testing & Validation

Test Checklist

Phase 1: Local Testing

  • User data exposed to JavaScript correctly
  • contactSupport() function defined
  • Button/link triggers function properly
  • Console shows no JavaScript errors

Phase 2: Authentication Flow

  • Logged-out users redirected to login
  • Logged-in users redirected to ticket system
  • User data passed correctly (check Network tab)
  • New tab opens (if configured)

Phase 3: Ticket System

  • User automatically logged in to ticket system
  • User redirected to correct dashboard
  • Can create tickets successfully
  • Session persists across page reloads

Phase 4: Edge Cases

  • Works with special characters in names/emails
  • Handles missing user data gracefully
  • Works on mobile devices
  • Works across different browsers

Testing Tools

Browser Console Test

// Test 1: Check user data
console.log('User Data:', window.authUser);

// Test 2: Check localStorage
console.log('Stored Email:', localStorage.getItem('yourcompany_user_email'));
console.log('Stored Name:', localStorage.getItem('yourcompany_user_name'));

// Test 3: Manually trigger function
contactSupport(null, false); // Opens in same tab for testing

Network Tab Inspection

  1. Open browser DevTools (F12)
  2. Go to Network tab
  3. Click "Submit Ticket" button
  4. Look for POST request to tickets.flare99.com
  5. Check payload contains email and name

🐛 Troubleshooting

Issue 1: "User data not found" error

Symptoms: Console shows window.authUser is null or undefined

Solution:

// Check if user authentication is working
console.log('Auth User:', window.authUser);

// Verify session/authentication
// Laravel: Auth::check()
// WordPress: is_user_logged_in()

Issue 2: CORS errors in console

Symptoms: Access-Control-Allow-Origin error in console

Solutions:

  1. Use Form POST method instead of AJAX (recommended)
  2. Contact us to add your domain to CORS whitelist
  3. Verify HTTPS is enabled on your site

Issue 3: Token expired error

Symptoms: Redirect fails with "Token expired" message

Solution:

  • Tokens are valid for 2 minutes
  • Ensure clock sync on server
  • User should click button shortly after page load

Issue 4: User not auto-logged in

Symptoms: User redirected but must login again

Solutions:

  1. Verify cookies are enabled in browser
  2. Check SameSite cookie settings
  3. Ensure user email matches exactly
  4. Contact us to verify tenant configuration

Issue 5: Button does nothing

Symptoms: Clicking button has no effect

Solutions:

// Check function is defined
console.log(typeof contactSupport); // Should output "function"

// Check for JavaScript errors
// Open DevTools Console tab
// Look for red error messages

// Verify event handler
document.querySelector('your-button-selector').onclick = contactSupport;

📡 API Reference

Endpoint: POST /api/auth/redirect/{tenant}

Authenticates user and redirects to tenant-specific ticket system.

Request

URL: /api/auth/redirect/{tenant}

Method: POST

Headers:

Content-Type: application/json
Accept: application/json

Body Parameters:

Parameter Type Required Description
email string Yes User's email address
name string Yes User's full name
redirect_url string No URL to redirect after auth (default: dashboard)

Example Request:

{
    "email": "user@example.com",
    "name": "John Doe",
    "redirect_url": "https://ticket.yourcompany.com/tickets/create"
}

Response

Success (302 Redirect):

HTTP/1.1 302 Found
Location: https://ticket.yourcompany.com/auth/callback?token=encrypted_token

Error (422 Validation Error):

{
    "message": "The given data was invalid.",
    "errors": {
        "email": ["The email field is required."],
        "name": ["The name field is required."]
    }
}

Error (404 Not Found):

{
    "message": "Tenant not found.",
    "error": "The specified tenant does not exist."
}

Error (429 Too Many Requests):

{
    "message": "Too many requests.",
    "retry_after": 60
}

Rate Limiting

  • Limit: 60 requests per hour per IP address
  • Header: X-RateLimit-Limit: 60
  • Remaining: X-RateLimit-Remaining: 59

📞 Support & Contact

Technical Support

Integration Assistance

Business Inquiries


📄 Changelog

Version 1.0 (October 27, 2025)

  • Initial release
  • Form-based POST integration
  • AJAX/Fetch API support
  • localStorage persistence
  • postMessage cross-domain communication
  • Comprehensive examples for Laravel, WordPress, React

📜 License & Terms

By integrating with our ticket system, you agree to:

  1. Data Privacy: Handle user data securely and comply with privacy regulations
  2. API Usage: Respect rate limits and usage guidelines
  3. Attribution: Maintain attribution links where applicable
  4. Updates: Keep integration code updated with latest security patches

For full terms of service, visit: https://tickets.flare99.com/terms


Thank you for choosing our ticket system! We're here to help. 🎫