Answers.Body: <p>My understanding is that Lobo's answer above is slightly misleading (at least if you read it 100% literally--the gist what he is saying is exactly correct, as usual, but the exact terminology may lead some of us astray).</p>
  
  <p>The <em>contact hash</em> is a value stored in the civicrm_contact table of the database (i.e., <em>civicrm_contact.hash</em>). </p>
  
  <p>The <em>contact hash</em> is used to generate the <em>contact checksum</em>, which is more precisely what Lobo is discussing above. It's easy to conflate to two, because they are closely related.  To add to the confusion, the <em>contact checksum</em> is itself a type of hash--but a different one from that hash found in the database under <em>civicrm_contact.hash</em>.</p>
  
  <p>The <em>contact checksum</em> isn't stored in the database but is generated afresh by a call to a CiviCRM function each time it is used. The <em>checksum</em> encodes the time it was generated and also the time it should expire, along with the pertinent civicrm_contact.hash to make a new hash. So the <em>checksum</em> is designed to be shared (e.g. with the contact associated with it) to allow temporary access to various parts of CiviCRM, and it expires after a set period.  By default, checksums that civicrm generates will expire after 7 days.  But tou can set that expiration time period to whatever you want, including infinite, when you request a checksum to be generated.</p>
  
  <p>The <em>civicrm_contact.hash</em>, by contrast is a <em>secret</em> and shouldn't be shared publicly--probably not even with the contact.  It is something like the user's password, and someone with the <em>contact hash</em> could use it to permanently gain access to do anything with that contact that they could do with a valid <em>checksum</em>: edit that contact's information, view payment and general CiviCRM history for that contact, register for events or making payments on behalf of that contact, etc. </p>
  
  <p>Also, as far as I know, the contact hash is never automatically regenerated.  (If it were ever changed or regenerated, it would immediately invalidate any checksums that happened to have been recently issued for that contact--generally not something that you would want to do.  If you want to give temporary access that expires, you would send them a checksum that expires, not change the hash.)</p>
  
  <p>So leaking the hash is not quite as serious as, say, leaking a person's Drupal password, but it is still a privacy breach and something you'll want to avoid in almost all cases I can imagine.</p>
  
  <p>Just for example, someone with the hash could generate a valid checksum to allow access to that CiviCRM contact at any time.</p>
  
  <p>In short, when working to allow contacts temporary/non-password access to view or update their account info, you want to use the <em>checksum</em>--which is *based on the *contact hash** but not the <em>hash</em> itself.  The <em>hash</em> is a secret and you should keep it secret.</p>
  
  <p>An example of how to get the contact's checksum &amp; turn it into a URL that could be used to edit the contact's profile:</p>
  
  <pre><code>// initialize civicrm stuff
  // Source: https://forum.civicrm.org/index.php?topic=21438.0
  civicrm_initialize(true);
  require_once(drupal_get_path('module', 'civicrm').'/../CRM/Contact/BAO/Contact/Utils.php');
  require_once(drupal_get_path('module', 'civicrm').'/../CRM/Utils/Mail.php');
  
  // try looking up the contact
  $result = civicrm_api('Contact', 'get', array('email' =&gt; $email, 'version' =&gt; 3));
  foreach($result['values'] as $contact) {
      // generate a url for this contact
      $checksum = CRM_Contact_BAO_Contact_Utils::generateChecksum($contact['contact_id'], time(), 24); // 24 hour checksum
      $query = "reset=1&amp;gid=9&amp;id=".$contact['contact_id']."&amp;".$checksum;
      $url = CRM_Utils_System::url('civicrm/profile/edit', $query, true, null, false);
  </code></pre>
  
  <p>Code from CRM/Contact/BAO/Contact/Utils.php showing the header for the checksum generation function</p>
  
  <pre><code>  /**
     * Generate a checksum for a contactID
     *
     * @param int    $contactID
     * @param int    $ts         timestamp that checksum was generated
     * @param int    $live       life of this checksum in hours/ 'inf' for infinite
     * @param string $hash       contact hash, if sent, prevents a query in inner loop
     *
     * @return array ( $cs, $ts, $live )
     * @static
     * @access public
     */
    static
    function generateChecksum($contactID, $ts = NULL, $live = NULL, $hash = NULL) {
  </code></pre>
  
  <p>Header from Utils.php showing how to use the checksum validate function:</p>
  
  <pre><code>  /**
     * Make sure the checksum is valid for the passed in contactID
     *
     * @param int    $contactID
     * @param string $inputCheck the checksum to validate
     *
     * @return boolean           true if valid, else false
     * @static
     * @access public
     */
    static
    function validChecksum($contactID, $inputCheck)  ...
  </code></pre>
  
  <p>Sources: <a href="https://wiki.civicrm.org/confluence/display/CRMDOC/Tokens" rel="noreferrer">https://wiki.civicrm.org/confluence/display/CRMDOC/Tokens</a></p>
  
  <p><a href="https://civicrm.stackexchange.com/questions/4683/get-or-generate-a-contact-checksum-via-api">Get or generate a contact checksum via API?</a></p>
  
  <p><a href="https://drupal.stackexchange.com/questions/140841/how-to-ensure-civicrm-checksum-cid-are-valid-in-custom-drupal-module">https://drupal.stackexchange.com/questions/140841/how-to-ensure-civicrm-checksum-cid-are-valid-in-custom-drupal-module</a></p>
  
  <p><a href="http://backofficethinking.com/blog/civicrm-tip-did-you-know-you-can-use-checksum-tokens-webforms" rel="noreferrer">http://backofficethinking.com/blog/civicrm-tip-did-you-know-you-can-use-checksum-tokens-webforms</a></p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-01-13T19:08:27.563Z
Answers.Text: Whoa.  I don't know who you are, but your first answer definitively corrected Lobo, who started the CiviCRM project.
Answers.UserDisplayName: Jon G - Megaphone Tech
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-11-18T16:43:11.893Z
Answers.Text: This answer helped a lot. I notice that the contact's hash is available as a field in Views so it's tempting to use but looks like I should avoid this if at all possible.
Answers.UserDisplayName: herb
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-01-13T18:06:38.430Z
Answers.LastActivityDate: 2017-01-13T18:06:38.430Z
Answers.LastEditDate: 2017-04-13T12:53:13.167Z
Answers.UserDisplayName: flug
Answers.Body: <ol>
  <li><p>Yes contact hashes are regenerated every time they are created. the microtime is embedded in the contact hash.</p></li>
  <li><p>Contact hashes have a specific life time (by default, this is 7 days). So they are invalid after 7 days</p></li>
  </ol>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-01-13T23:27:03.233Z
Answers.Text: Perhaps worth noting that the "7 days" is configurable via the UI at Admin > Settings > Misc ie civicrm/admin/setting/misc?reset=1
Answers.UserDisplayName: petednz - fuzion
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2015-04-10T00:19:13.170Z
Answers.Text: "regenerated every time they are created", created or used?
  Or are they just regenerated on a time schedule?
Answers.UserDisplayName: Owen Kelly
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2015-04-10T03:32:17.757Z
Answers.Text: created == every time the code has to generate a contact hash. So for example, if u embed a contact hash token in a mailing, every time a mailing is sent to a person, the contact hash is different. When a contact hash is used in a url (i.e. read) no change is made
Answers.UserDisplayName: Donald Lobo
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2015-04-10T03:33:23.213Z
Answers.Text: Ah yep. So they're regenerate weekly, and that's it. Thanks for the help lobo
Answers.UserDisplayName: Owen Kelly
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2015-04-09T16:10:25.080Z
Answers.LastActivityDate: 2015-04-09T16:10:25.080Z
Answers.UserDisplayName: Donald Lobo
Body: <p>Currently we don't use contact hashes but we'd really like to.</p>
  
  <p>My understanding is that contact hashes are exposed as a token that can be used in CiviMail where they are appended to links. They're unique to each user (stored in the contact table), and they look like they're an <code>md5</code> of something.</p>
  
  <p>We're able to use them fine, but my question is around they work.</p>
  
  <p><strong>Are they ever regenerated?</strong></p>
  
  <p><strong>Are there best practices to keeping them secure?</strong></p>
  
  <p>From what I can gather they carry the same privacy considerations as a forgot password link. Though where a forgot password link give the link holder full control of the account, the contact hash only allows forms to be prefilled (still exposes PII).</p>
  
  <p>I'm lead to believe contact hashes should be regenerated within a hour of being clicked (some people might stuff something up, and need to click the link again).</p>
  
  <p>Can anyone shed any light on this?</p>
  
  <p><em>(sorry for the brain dump)</em></p>
  
Tags: <civimail><best-practice><tokens>
Title: How do contact hashes work, and how do I keep them secure?
ThreadText: # How do contact hashes work, and how do I keep them secure?
  
  (Asked by: username_0 on 2015-04-09)
  
  Currently we don't use contact hashes but we'd really like to.
  
  My understanding is that contact hashes are exposed as a token that can be used in CiviMail where they are appended to links. They're unique to each user (stored in the contact table), and they look like they're an `md5` of something.
  
  We're able to use them fine, but my question is around they work.
  
  **Are they ever regenerated?**
  
  **Are there best practices to keeping them secure?**
  
  From what I can gather they carry the same privacy considerations as a forgot password link. Though where a forgot password link give the link holder full control of the account, the contact hash only allows forms to be prefilled (still exposes PII).
  
  I'm lead to believe contact hashes should be regenerated within a hour of being clicked (some people might stuff something up, and need to click the link again).
  
  Can anyone shed any light on this?
  
  *(sorry for the brain dump)*
  
  **Tags:** civimail, best-practice, tokens
  
  
  ---
  
  ## 2 answers
  
  ### Answer by username_4 on 2015-04-09. Score: 5 | Accepted answer
  
  1. Yes contact hashes are regenerated every time they are created. the microtime is embedded in the contact hash.
  2. Contact hashes have a specific life time (by default, this is 7 days). So they are invalid after 7 days
  
  > **Comments:**
  > **username_0**: "regenerated every time they are created", created or used? Or are they just regenerated on a time schedule?  
  > **username_4**: created == every time the code has to generate a contact hash. So for example, if u embed a contact hash token in a mailing, every time a mailing is sent to a person, the contact hash is different. When a contact hash is used in a url (i.e. read) no change is made  
  > **username_0**: Ah yep. So they're regenerate weekly, and that's it. Thanks for the help lobo  
  > **username_5**: Perhaps worth noting that the "7 days" is configurable via the UI at Admin > Settings > Misc ie civicrm/admin/setting/misc?reset=1  
  
  ---
  
  ### Answer by username_1 on 2017-01-13. Score: 12
  
  My understanding is that Lobo's answer above is slightly misleading (at least if you read it 100% literally--the gist what he is saying is exactly correct, as usual, but the exact terminology may lead some of us astray).
  The contact hash is a value stored in the civicrm_contact table of the database (i.e., civicrm_contact.hash). 
  The contact hash is used to generate the contact checksum, which is more precisely what Lobo is discussing above. It's easy to conflate to two, because they are closely related.  To add to the confusion, the contact checksum is itself a type of hash--but a different one from that hash found in the database under civicrm_contact.hash.
  The contact checksum isn't stored in the database but is generated afresh by a call to a CiviCRM function each time it is used. The checksum encodes the time it was generated and also the time it should expire, along with the pertinent civicrm_contact.hash to make a new hash. So the checksum is designed to be shared (e.g. with the contact associated with it) to allow temporary access to various parts of CiviCRM, and it expires after a set period.  By default, checksums that civicrm generates will expire after 7 days.  But tou can set that expiration time period to whatever you want, including infinite, when you request a checksum to be generated.
  The civicrm_contact.hash, by contrast is a secret and shouldn't be shared publicly--probably not even with the contact.  It is something like the user's password, and someone with the contact hash could use it to permanently gain access to do anything with that contact that they could do with a valid checksum: edit that contact's information, view payment and general CiviCRM history for that contact, register for events or making payments on behalf of that contact, etc. 
  Also, as far as I know, the contact hash is never automatically regenerated.  (If it were ever changed or regenerated, it would immediately invalidate any checksums that happened to have been recently issued for that contact--generally not something that you would want to do.  If you want to give temporary access that expires, you would send them a checksum that expires, not change the hash.)
  So leaking the hash is not quite as serious as, say, leaking a person's Drupal password, but it is still a privacy breach and something you'll want to avoid in almost all cases I can imagine.
  Just for example, someone with the hash could generate a valid checksum to allow access to that CiviCRM contact at any time.
  In short, when working to allow contacts temporary/non-password access to view or update their account info, you want to use the checksum--which is *based on the *contact hash** but not the hash itself.  The hash is a secret and you should keep it secret.
  An example of how to get the contact's checksum & turn it into a URL that could be used to edit the contact's profile:
  // initialize civicrm stuff
  // Source: https://forum.civicrm.org/index.php?topic=21438.0
  civicrm_initialize(true);
  require_once(drupal_get_path('module', 'civicrm').'/../CRM/Contact/BAO/Contact/Utils.php');
  require_once(drupal_get_path('module', 'civicrm').'/../CRM/Utils/Mail.php');
  
  // try looking up the contact
  $result = civicrm_api('Contact', 'get', array('email' => $email, 'version' => 3));
  foreach($result['values'] as $contact) {
      // generate a url for this contact
      $checksum = CRM_Contact_BAO_Contact_Utils::generateChecksum($contact['contact_id'], time(), 24); // 24 hour checksum
      $query = "reset=1&gid=9&id=".$contact['contact_id']."&".$checksum;
      $url = CRM_Utils_System::url('civicrm/profile/edit', $query, true, null, false);
  
  Code from CRM/Contact/BAO/Contact/Utils.php showing the header for the checksum generation function
    /**
     * Generate a checksum for a contactID
     *
     * @param int    $contactID
     * @param int    $ts         timestamp that checksum was generated
     * @param int    $live       life of this checksum in hours/ 'inf' for infinite
     * @param string $hash       contact hash, if sent, prevents a query in inner loop
     *
     * @return array ( $cs, $ts, $live )
     * @static
     * @access public
     */
    static
    function generateChecksum($contactID, $ts = NULL, $live = NULL, $hash = NULL) {
  
  Header from Utils.php showing how to use the checksum validate function:
    /**
     * Make sure the checksum is valid for the passed in contactID
     *
     * @param int    $contactID
     * @param string $inputCheck the checksum to validate
     *
     * @return boolean           true if valid, else false
     * @static
     * @access public
     */
    static
    function validChecksum($contactID, $inputCheck)  ...
  
  Sources: https://wiki.civicrm.org/confluence/display/CRMDOC/Tokens
  Get or generate a contact checksum via API?
  https://drupal.stackexchange.com/questions/140841/how-to-ensure-civicrm-checksum-cid-are-valid-in-custom-drupal-module
  http://backofficethinking.com/blog/civicrm-tip-did-you-know-you-can-use-checksum-tokens-webforms
  
  > **Comments:**
  > **username_2**: Whoa.  I don't know who you are, but your first answer definitively corrected Lobo, who started the CiviCRM project.  
  > **username_3**: This answer helped a lot. I notice that the contact's hash is available as a field in Views so it's tempting to use but looks like I should avoid this if at all possible.  
  
  ---
  
  