Skip to content

Instantly share code, notes, and snippets.

@lynt-smitka
Last active April 3, 2025 14:47
Show Gist options
  • Save lynt-smitka/0e9f5fd946fdc1523a2df20983174fb7 to your computer and use it in GitHub Desktop.
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.
<?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