diff --git a/modules/openid/openid.module b/modules/openid/openid.module
index ed914397cdc68957e01fbc781c37ccb3a93e9423..e3128665a0e36a38f87608f306f7376ac5723df2 100644
--- a/modules/openid/openid.module
+++ b/modules/openid/openid.module
@@ -341,14 +341,18 @@ function openid_complete($response = array()) {
             $response['openid.claimed_id'] = $service['claimed_id'];
           }
           elseif ($service['version'] == 2) {
-            $response['openid.claimed_id'] = openid_normalize($response['openid.claimed_id']);
+            // Returned Claimed Identifier could contain unique fragment
+            // identifier to allow identifier recycling so we need to preserve
+            // it in the response.
+            $response_claimed_id = openid_normalize($response['openid.claimed_id']);
+
             // OpenID Authentication, section 11.2:
             // If the returned Claimed Identifier is different from the one sent
             // to the OpenID Provider, we need to do discovery on the returned
             // 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']);
+            if ($response_claimed_id != $claimed_id) {
+              $services = openid_discovery($response_claimed_id);
               $uris = array();
               foreach ($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'])) {
diff --git a/modules/openid/openid.test b/modules/openid/openid.test
index 202a8355ea2aa1a1459d69d17f98d1bc5af2eb2c..09632ba1417c74465a71482dc5ea37592c41e869 100644
--- a/modules/openid/openid.test
+++ b/modules/openid/openid.test
@@ -89,12 +89,12 @@ class OpenIDFunctionalTestCase extends OpenIDWebTestCase {
     // Identifier is the URL of an XRDS document containing an OP Identifier
     // Element. The Relying Party sends the special value
     // "http://specs.openid.net/auth/2.0/identifier_select" as Claimed
-    // Identifier. The OpenID Provider responds with the actual identifier.
-    $identity = url('openid-test/yadis/xrds/dummy-user', array('absolute' => TRUE));
-    // Tell openid_test.module to respond with this identifier. The URL scheme
-    // is stripped in order to test that the returned identifier is normalized in
-    // openid_complete().
-    variable_set('openid_test_response', array('openid.claimed_id' => preg_replace('@^https?://@', '', $identity)));
+    // Identifier. The OpenID Provider responds with the actual identifier
+    // including the fragment.
+    $identity = url('openid-test/yadis/xrds/dummy-user', array('absolute' => TRUE, 'fragment' => $this->randomName()));
+    // Tell openid_test.module to respond with this identifier. We test if
+    // openid_complete() processes it right.
+    variable_set('openid_test_response', array('openid.claimed_id' => $identity));
     $this->addIdentity(url('openid-test/yadis/xrds/server', array('absolute' => TRUE)), 2, 'http://specs.openid.net/auth/2.0/identifier_select', $identity);
     variable_set('openid_test_response', array());