Last active
April 3, 2025 14:47
-
-
Save lynt-smitka/0e9f5fd946fdc1523a2df20983174fb7 to your computer and use it in GitHub Desktop.
WordPress cross-domain login system that auto-authenticates users across multiple Polylang language domains using secure AJAX calls.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// Get site domains from Polylang | |
function lynt_get_domains() { | |
$domains = []; | |
if (function_exists('pll_languages_list')) { | |
$languages = pll_languages_list(array('fields' => 'home_url')); | |
foreach ($languages as $home_url) { | |
$domain = parse_url($home_url, PHP_URL_HOST); | |
if (!empty($domain)) { | |
$domains[] = $domain; | |
} | |
} | |
} | |
return apply_filters('lynt_login_domains', $domains); | |
} | |
function lynt_initialize_cross_login() { | |
// Only run on the dashboard page | |
$screen = get_current_screen(); | |
if (!$screen || $screen->id !== 'dashboard') { | |
return; | |
} | |
add_action('admin_footer', 'lynt_render_cross_login_script'); | |
} | |
// Add script for multi-domain login to dashboard | |
function lynt_render_cross_login_script() { | |
$domains = lynt_get_domains(); | |
$user_id = get_current_user_id(); | |
if ($user_id > 0) { | |
// Create a signature for secure transmission of user ID | |
$timestamp = time(); | |
$signature = hash_hmac('sha256', $user_id . '|' . $timestamp, AUTH_KEY . SECURE_AUTH_KEY); | |
?> | |
<script> | |
jQuery(document).ready(function($) { | |
var currentHost = location.host; | |
var loginData = { | |
'action': 'lynt_manage', | |
'cmd': 'login', | |
'user_id': <?php echo intval($user_id); ?>, | |
'timestamp': <?php echo intval($timestamp); ?>, | |
'signature': '<?php echo esc_js($signature); ?>' | |
}; | |
var domains = <?php echo json_encode($domains); ?>; | |
domains.forEach(function(domain) { | |
if (domain !== currentHost) { | |
$.ajax({ | |
type: "POST", | |
url: "https://" + domain + "/wp-admin/admin-ajax.php", | |
data: loginData, | |
xhrFields: { withCredentials: true } | |
}); | |
} | |
}); | |
}); | |
</script> | |
<?php | |
} | |
} | |
// Handle AJAX - login process | |
function lynt_manage() { | |
// Set CORS | |
lynt_add_cors_headers(); | |
// Init result | |
$result = [ | |
'status' => 'error', | |
'message' => 'Invalid request' | |
]; | |
// Validate | |
if (!isset($_POST['cmd']) || !isset($_POST['user_id']) || !isset($_POST['timestamp']) || !isset($_POST['signature'])) { | |
wp_send_json($result); | |
return; | |
} | |
// Sanitize | |
$cmd = sanitize_text_field($_POST['cmd']); | |
$user_id = intval($_POST['user_id']); | |
$timestamp = intval($_POST['timestamp']); | |
$signature = sanitize_text_field($_POST['signature']); | |
if ($cmd === 'login' && is_user_logged_in()) { | |
$result = [ | |
'status' => 'info', | |
'message' => 'User already logged in', | |
]; | |
wp_send_json($result); | |
return; | |
} | |
// Process login command | |
if ($cmd === 'login' && !is_user_logged_in()) { | |
// Verify timestamp < 5 minutes | |
if (time() - $timestamp > 300) { | |
$result['message'] = 'Request expired'; | |
wp_send_json($result); | |
return; | |
} | |
// Verify signature | |
$expected_signature = hash_hmac('sha256', $user_id . '|' . $timestamp, AUTH_KEY . SECURE_AUTH_KEY); | |
if (!hash_equals($expected_signature, $signature)) { | |
$result['message'] = 'Invalid signature'; | |
wp_send_json($result); | |
return; | |
} | |
// Check user exists | |
$user = get_user_by('id', $user_id); | |
if (!$user) { | |
$result['message'] = 'User does not exist'; | |
wp_send_json($result); | |
return; | |
} | |
// Generate auth cookies | |
$expiration = time() + 8 * HOUR_IN_SECONDS; | |
$expire = $expiration + (1 * HOUR_IN_SECONDS); | |
$secure = true; // Vždy nastavit jako secure | |
$auth_cookie = wp_generate_auth_cookie($user_id, $expiration, 'secure_auth'); | |
$logged_in_cookie = wp_generate_auth_cookie($user_id, $expiration, 'logged_in'); | |
// Set cookies with SameSite=None (it will slightly decrease SECURITY) | |
setcookie( | |
SECURE_AUTH_COOKIE, | |
$auth_cookie, | |
[ | |
'expires' => $expire, | |
'path' => ADMIN_COOKIE_PATH, | |
'domain' => COOKIE_DOMAIN, | |
'secure' => $secure, | |
'httponly' => true, | |
'samesite' => 'None' | |
] | |
); | |
setcookie( | |
LOGGED_IN_COOKIE, | |
$logged_in_cookie, | |
[ | |
'expires' => $expire, | |
'path' => COOKIEPATH, | |
'domain' => COOKIE_DOMAIN, | |
'secure' => $secure, | |
'httponly' => true, | |
'samesite' => 'None' | |
] | |
); | |
// Optional call wp_login e.g. for auditing | |
// do_action('wp_login', $user->user_login, $user); | |
$result = [ | |
'status' => 'success', | |
'message' => 'Login successful' | |
]; | |
} | |
wp_send_json($result); | |
} | |
// Set CORS headers for cross-domain requests | |
function lynt_add_cors_headers() { | |
$allowed_domains = lynt_get_domains(); | |
// Check if request is from an allowed origin | |
if (isset($_SERVER['HTTP_ORIGIN'])) { | |
$origin = $_SERVER['HTTP_ORIGIN']; | |
$domain = parse_url($origin, PHP_URL_HOST); | |
if (in_array($domain, $allowed_domains)) { | |
// Set CORS headers | |
header('Access-Control-Allow-Origin: ' . $origin); | |
header('Access-Control-Allow-Credentials: true'); | |
} | |
} | |
} | |
add_action('current_screen', 'lynt_initialize_cross_login'); | |
add_action('wp_ajax_nopriv_lynt_manage', 'lynt_manage'); | |
add_action('wp_ajax_lynt_manage', 'lynt_manage'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment