diff --git a/modules/openid/openid.api.php b/modules/openid/openid.api.php
index 11faa71..b94fa86 100644
--- a/modules/openid/openid.api.php
+++ b/modules/openid/openid.api.php
@@ -49,8 +49,9 @@ function hook_openid_response($response, $account) {
  * Allow modules to declare OpenID discovery methods.
  *
  * The discovery function callbacks will be called in turn with an unique
- * parameter, the claimed identifier. They have to return an array of services,
- * in the same form returned by openid_discover().
+ * parameter, the claimed identifier. They have to return a structured array
+ * with arrays of services and claimed id in the same form returned by
+ * openid_discover().
  *
  * The first discovery method that succeed (return at least one services) will
  * stop the discovery process.
diff --git a/modules/openid/openid.module b/modules/openid/openid.module
index 7673de8..5151eb8 100644
--- a/modules/openid/openid.module
+++ b/modules/openid/openid.module
@@ -256,16 +256,24 @@ function openid_login_validate($form, &$form_state) {
 function openid_begin($claimed_id, $return_to = '', $form_values = array()) {
   module_load_include('inc', 'openid');
 
+  $service = NULL;
   $claimed_id = openid_normalize($claimed_id);
 
-  $services = openid_discovery($claimed_id);
-  $service = _openid_select_service($services);
+  $discovery = openid_discovery($claimed_id);
+  if (!empty($discovery['services'])) {
+    $service = _openid_select_service($discovery['services']);
+  }
 
   if (!$service) {
     form_set_error('openid_identifier', t('Sorry, that is not a valid OpenID. Ensure you have spelled your ID correctly.'));
     return;
   }
 
+  // Set claimed_id from discovery
+  if (!empty($service['claimed_id'])) {
+    $claimed_id = $discovery['claimed_id'];
+  }
+
   // Store discovered information in the users' session so we don't have to rediscover.
   $_SESSION['openid']['service'] = $service;
   // Store the claimed id
@@ -348,9 +356,9 @@ function openid_complete($response = array()) {
             // identififer to make sure that the provider is authorized to
             // respond on behalf of this.
             if ($response['openid.claimed_id'] != $claimed_id) {
-              $services = openid_discovery($response['openid.claimed_id']);
+              $discovery = openid_discovery($response['openid.claimed_id']);
               $uris = array();
-              foreach ($services as $discovered_service) {
+              foreach ($discovery['services'] as $discovered_service) {
                 if (in_array('http://specs.openid.net/auth/2.0/server', $discovered_service['types']) || in_array('http://specs.openid.net/auth/2.0/signon', $discovered_service['types'])) {
                   $uris[] = $discovered_service['uri'];
                 }
@@ -376,8 +384,8 @@ function openid_complete($response = array()) {
  *
  * @param $claimed_id The OpenID URL to perform discovery on.
  *
- * @return Array of services discovered (including OpenID version, endpoint
- * URI, etc).
+ * @return Structured array of discovered claimed_id and array of services
+ *   (including OpenID version, endpoint URI, etc).
  */
 function openid_discovery($claimed_id) {
   module_load_include('inc', 'openid');
@@ -385,11 +393,11 @@ function openid_discovery($claimed_id) {
   $methods = module_invoke_all('openid_discovery_method_info');
   drupal_alter('openid_discovery_method_info', $methods);
 
-  // Execute each method in turn.
+  // Execute each method in turn and return first successful discovery.
   foreach ($methods as $method) {
-    $discovered_services = $method($claimed_id);
-    if (!empty($discovered_services)) {
-      return $discovered_services;
+    $discovery = $method($claimed_id);
+    if (!empty($discovery)) {
+      return $discovery;
     }
   }
 
@@ -423,18 +431,26 @@ function _openid_xri_discovery($claimed_id) {
     // Resolve XRI using a proxy resolver (Extensible Resource Identifier (XRI)
     // Resolution Version 2.0, section 11.2 and 14.3).
     $xrds_url = variable_get('xri_proxy_resolver', 'http://xri.net/') . rawurlencode($claimed_id) . '?_xrd_r=application/xrds+xml';
-    $services = _openid_xrds_discovery($xrds_url);
-    foreach ($services as $i => &$service) {
-      $status = $service['xrd']->children(OPENID_NS_XRD)->Status;
-      if ($status && $status->attributes()->cid == 'verified') {
-        $service['claimed_id'] = openid_normalize((string)$service['xrd']->children(OPENID_NS_XRD)->CanonicalID);
+    $discovery = _openid_xrds_discovery($xrds_url);
+    if (!empty($discovery['services']) && is_array($discovery['services'])) {
+      foreach ($discovery['services'] as $i => &$service) {
+        $status = $service['xrd']->children(OPENID_NS_XRD)->Status;
+        if ($status && $status->attributes()->cid == 'verified') {
+          $service['claimed_id'] = openid_normalize((string)$service['xrd']->children(OPENID_NS_XRD)->CanonicalID);
+        }
+        else {
+          // Ignore service if CanonicalID could not be verified.
+          unset($discovery['services'][$i]);
+        }
       }
-      else {
-        // Ignore service if CanonicalID could not be verified.
-        unset($services[$i]);
+      if (!empty($discovery['services'])) {
+        // TODO: maybe we can just return $discovery itself
+        return array(
+          'services' => $discovery['services'],
+          'claimed_id' => $discovery['claimed_id'],
+        );
       }
     }
-    return $services;
   }
 }
 
@@ -454,7 +470,18 @@ function _openid_xrds_discovery($claimed_id) {
     $headers = array('Accept' => 'application/xrds+xml');
     $result = drupal_http_request($xrds_url, array('headers' => $headers));
 
-    if (!isset($result->error)) {
+    // Check for HTTP error and make sure, that we reach the target. If maximum
+    // allowed redirects are exhausted, final destination URL isn't reached, but
+    // drupal_http_request will not return error. (This check for 200 result
+    // code could be removed after http://drupal.org/node/1096890 will be
+    // fixed.)
+    if (!isset($result->error) && $result->code == 200) {
+
+      // Replace user entered claimed_id if we got redirect
+      if (!empty($result->redirect_url)) {
+        $claimed_id = openid_normalize($result->redirect_url);
+      }
+
       if (isset($result->headers['content-type']) && preg_match("/application\/xrds\+xml/", $result->headers['content-type'])) {
         // Parse XML document to find URL
         $services = _openid_xrds_parse($result->data);
@@ -500,7 +527,13 @@ function _openid_xrds_discovery($claimed_id) {
       }
     }
   }
-  return $services;
+
+  if (!empty($services)) {
+    return array(
+      'services' => $services,
+      'claimed_id' => $claimed_id,
+    );
+  }
 }
 
 /**
