/* ======================================================================== * API: VERIFY XCOJO CENTRAL SESSION * ====================================================================== */ if ($action === 'verify-session') { /* * Product-to-Central-Identity authentication key. * * IMPORTANT: * Replace this value with the SAME secret configured in every * *.xcojo.com product that calls this endpoint. */ $sharedKey = defined('PRODUCTS_SHARED_KEY') ? (string) PRODUCTS_SHARED_KEY : ''; if ( $sharedKey === '' || $sharedKey === 'CHANGE_ME_PRODUCTS_KEY' ) { xcojo_json([ 'valid' => false, 'error' => 'Server not configured' ], 500); } /* * Verify the calling Xcojo product. */ $givenKey = $_SERVER['HTTP_X_XCOJO_KEY'] ?? ''; if ( $givenKey === '' || !hash_equals($sharedKey, $givenKey) ) { xcojo_json([ 'valid' => false, 'error' => 'Unauthorized' ], 401); } /* * Obtain the Central Identity session token. * * Supports: * POST token=... * X-Xcojo-Session-Token header * xcojo_session cookie */ $sessionToken = trim((string)($_POST['token'] ?? '')) ?: trim((string)($_SERVER['HTTP_X_XCOJO_SESSION_TOKEN'] ?? '')) ?: trim((string)($_COOKIE['xcojo_session'] ?? '')); if ($sessionToken === '') { xcojo_json([ 'valid' => false, 'error' => 'No token provided' ], 400); } /* * Never store the raw session token in MariaDB. * The sessions table stores only the SHA-512 token hash. */ $tokenHash = hash('sha512', $sessionToken); /* * Central Identity session lookup. * * Uses the new Central Identity schema: * * sessions.session_id * sessions.xcojo_uid * sessions.expires_at * users.xcojo_uid */ try { $stmt = $db->prepare( "SELECT s.session_id, s.xcojo_uid, s.ip_address, s.user_agent, s.created_at AS session_created_at, s.expires_at, u.xcojo_uid, u.connect_handle, u.first_name, u.last_name, u.birth_date, u.gender, u.external_email, u.avatar_url, u.is_active, u.external_email_verified, u.tos_accepted, u.created_at AS user_created_at, u.updated_at AS user_updated_at FROM sessions s INNER JOIN users u ON u.xcojo_uid = s.xcojo_uid WHERE s.session_id = ? AND s.expires_at > CURRENT_TIMESTAMP AND u.is_active = 1 LIMIT 1" ); /* * IMPORTANT: * * In the Central Identity schema session_id is the primary key. * It contains the random session token itself. */ $stmt->execute([$sessionToken]); $user = $stmt->fetch(PDO::FETCH_ASSOC); } catch (PDOException $e) { error_log( '[xcojo] verify-session database error: ' . $e->getMessage() ); xcojo_json([ 'valid' => false, 'error' => 'Authentication service database error' ], 500); } if (!$user) { xcojo_json([ 'valid' => false, 'error' => 'Invalid or expired session' ], 401); } /* * Return only information products actually need. * * Do NOT return password_hash or other authentication secrets. */ xcojo_json([ 'valid' => true, 'session' => [ 'id' => $user['session_id'], 'created_at' => $user['session_created_at'], 'expires_at' => $user['expires_at'], ], 'user' => [ 'xcojo_uid' => $user['xcojo_uid'], 'connect_handle' => $user['connect_handle'], 'first_name' => $user['first_name'], 'last_name' => $user['last_name'], 'birth_date' => $user['birth_date'], 'gender' => $user['gender'], 'external_email' => $user['external_email'], 'avatar_url' => $user['avatar_url'], 'external_email_verified'=> (bool)$user['external_email_verified'], 'tos_accepted' => (bool)$user['tos_accepted'], ], ]); }