function WriteJsConnect($User, $Request, $ClientID, $Secret, $Secure = TRUE)
{
    $User = array_change_key_case($User);
    // Error checking.
    if ($Secure) {
        // Check the client.
        if (!isset($Request['client_id'])) {
            $Error = array('error' => 'invalid_request', 'message' => 'The client_id parameter is missing.');
        } elseif ($Request['client_id'] != $ClientID) {
            $Error = array('error' => 'invalid_client', 'message' => "Unknown client {$Request['client_id']}.");
        } elseif (!isset($Request['timestamp']) && !isset($Request['signature'])) {
            if (is_array($User) && count($User) > 0) {
                // This isn't really an error, but we are just going to return public information when no signature is sent.
                $Error = array('name' => $User['name'], 'photourl' => @$User['photourl']);
            } else {
                $Error = array('name' => '', 'photourl' => '');
            }
        } elseif (!isset($Request['timestamp']) || !is_numeric($Request['timestamp'])) {
            $Error = array('error' => 'invalid_request', 'message' => 'The timestamp parameter is missing or invalid.');
        } elseif (!isset($Request['signature'])) {
            $Error = array('error' => 'invalid_request', 'message' => 'Missing  signature parameter.');
        } elseif (($Diff = abs($Request['timestamp'] - JsTimestamp())) > JS_TIMEOUT) {
            $Error = array('error' => 'invalid_request', 'message' => 'The timestamp is invalid.');
        } else {
            // Make sure the timestamp hasn't timed out.
            $Signature = md5($Request['timestamp'] . $Secret);
            if ($Signature != $Request['signature']) {
                $Error = array('error' => 'access_denied', 'message' => 'Signature invalid.');
            }
        }
    }
    if (isset($Error)) {
        $Result = $Error;
    } elseif (is_array($User) && count($User) > 0) {
        if ($Secure === NULL) {
            $Result = $User;
        } else {
            $Result = SignJsConnect($User, $ClientID, $Secret, TRUE);
        }
    } else {
        $Result = array('name' => '', 'photourl' => '');
    }
    $Json = json_encode($Result);
    if (isset($Request['callback'])) {
        header("Content-Type: application/javascript");
        echo "{$Request['callback']}({$Json});";
    } else {
        header("Content-Type: application/json");
        echo $Json;
    }
}
 /**
  *
  * @param EntryController $Sender
  * @param array $Args
  */
 public function Base_ConnectData_Handler($Sender, $Args)
 {
     if (GetValue(0, $Args) != 'jsconnect') {
         return;
     }
     include_once dirname(__FILE__) . '/functions.jsconnect.php';
     $Form = $Sender->Form;
     $JsConnect = $Form->GetFormValue('JsConnect', $Form->GetFormValue('Form/JsConnect'));
     parse_str($JsConnect, $JsData);
     // Make sure the data is valid.
     $client_id = GetValue('client_id', $JsData, GetValue('clientid', $JsData, $Sender->Request->Get('client_id'), TRUE), TRUE);
     $Signature = GetValue('signature', $JsData, FALSE, TRUE);
     $String = GetValue('sigStr', $JsData, FALSE, TRUE);
     // debugging
     unset($JsData['string']);
     if (!$client_id) {
         throw new Gdn_UserException(sprintf(T('ValidateRequired'), 'client_id'), 400);
     }
     $Provider = self::GetProvider($client_id);
     if (!$Provider) {
         throw new Gdn_UserException(sprintf(T('Unknown client: %s.'), $client_id), 400);
     }
     if (!GetValue('TestMode', $Provider)) {
         if (!$Signature) {
             throw new Gdn_UserException(sprintf(T('ValidateRequired'), 'signature'), 400);
         }
         // Validate the signature.
         $CalculatedSignature = SignJsConnect($JsData, $client_id, GetValue('AssociationSecret', $Provider), GetValue('HashType', $Provider, 'md5'));
         if ($CalculatedSignature != $Signature) {
             throw new Gdn_UserException(T("Signature invalid."), 400);
         }
     }
     // Map all of the standard jsConnect data.
     $Map = array('uniqueid' => 'UniqueID', 'name' => 'Name', 'email' => 'Email', 'photourl' => 'Photo');
     foreach ($Map as $Key => $Value) {
         $Form->SetFormValue($Value, GetValue($Key, $JsData, ''));
     }
     if (isset($JsData['roles'])) {
         $Form->SetFormValue('Roles', $JsData['roles']);
     }
     // Now add any extended information that jsConnect might have sent.
     $ExtData = array_diff_key($JsData, $Map);
     if (class_exists('SimpleAPIPlugin')) {
         SimpleAPIPlugin::TranslatePost($ExtData, FALSE);
     }
     Gdn::UserModel()->DefineSchema();
     $Keys = array_keys(Gdn::UserModel()->Schema->Fields());
     $UserFields = array_change_key_case(array_combine($Keys, $Keys));
     foreach ($ExtData as $Key => $Value) {
         $lkey = strtolower($Key);
         if (array_key_exists($lkey, $UserFields)) {
             $Form->SetFormValue($UserFields[$lkey], $Value);
         } else {
             $Form->SetFormValue($Key, $Value);
         }
     }
     $Form->SetFormValue('Provider', $client_id);
     $Form->SetFormValue('ProviderName', GetValue('Name', $Provider, ''));
     $Form->AddHidden('JsConnect', $JsData);
     $Sender->SetData('ClientID', $client_id);
     $Sender->SetData('Verified', TRUE);
     $Sender->SetData('Trusted', GetValue('Trusted', $Provider, TRUE));
     // this is a trusted connection.
     $Sender->SetData('SSOUser', $JsData);
 }