Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?

Intercom user_hash

Remember that your secret key should never be exposed to the public

  • So Javascript code below should only be used for testing unless modified and used to run on a server

Javascript

<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/hmac-sha256.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/components/enc-base64-min.js"></script>
<script>
  var hash = CryptoJS.HmacSHA256("Message", "secret");
  var hashInHex = CryptoJS.enc.Hex.stringify(hash);
  document.write(hashInHex); // aa747c502a898200f9e4fa21bac68136f886a0e27aec70ba06daf2e2a5cb5597
</script>

Node

const crypto = require('crypto');
const hmac = crypto.createHmac('sha256', 'secret');
hmac.update('Message');
console.log(hmac.digest('hex')); // aa747c502a898200f9e4fa21bac68136f886a0e27aec70ba06daf2e2a5cb5597

PHP

<?php
echo hash_hmac('sha256', 'Message', 'secret'); // thanks @AshleyPinner https://gist.github.com/thewheat/7342c76ade46e7322c3e#gistcomment-1820677
?>

Java

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class Test {
  public static void main(String[] args) {
  try {
      String secret = "secret";
      String message = "Message";

      Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
      SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
      sha256_HMAC.init(secret_key);

      byte[] hash = (sha256_HMAC.doFinal(message.getBytes()));
      StringBuffer result = new StringBuffer();
      for (byte b : hash) {
        result.append(String.format("%02x", b)); // thanks sachins! https://gist.github.com/thewheat/7342c76ade46e7322c3e#gistcomment-1863031 
      }
      System.out.println(result.toString()); // aa747c502a898200f9e4fa21bac68136f886a0e27aec70ba06daf2e2a5cb5597
    }
    catch (Exception e){
      System.out.println("Error");
    }
  }
}

Groovy

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;

def hmac_sha256(String secretKey, String data) {
 try {
    Mac mac = Mac.getInstance("HmacSHA256")
    SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256")
    mac.init(secretKeySpec)
    byte[] digest = mac.doFinal(data.getBytes())
    return digest
   } catch (InvalidKeyException e) {
    throw new RuntimeException("Invalid key exception while converting to HMac SHA256")
  }
}

def hash = hmac_sha256("secret", "Message")
StringBuffer result = new StringBuffer();
for (byte b : hash) {
result.append(String.format("%02x", b)); // thanks sachins! https://gist.github.com/thewheat/7342c76ade46e7322c3e#gistcomment-1863031
}
print(result.toString()); // aa747c502a898200f9e4fa21bac68136f886a0e27aec70ba06daf2e2a5cb5597

C#

using System.Security.Cryptography;

namespace Test
{
	public class MyHmac
	{
		public static void Main(string[] args){
			var hmac = new MyHmac ();
			System.Console.WriteLine(hmac.CreateToken ("Message", "secret")); // AA747C502A898200F9E4FA21BAC68136F886A0E27AEC70BA06DAF2E2A5CB5597
		}
		private string CreateToken(string message, string secret)
		{
			secret = secret ?? "";
			var encoding = new System.Text.ASCIIEncoding();
			byte[] keyByte = encoding.GetBytes(secret);
			byte[] messageBytes = encoding.GetBytes(message);
			using (var hmacsha256 = new HMACSHA256(keyByte))
			{
				byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);

				var sb = new System.Text.StringBuilder();
				for (var i = 0; i <= hashmessage.Length - 1; i++)
				{
					sb.Append(hashmessage[i].ToString("x2")); // Thanks! @ermirbeqiraj https://gist.github.com/thewheat/7342c76ade46e7322c3e#gistcomment-3180664
				}
				return sb.ToString();
			}
		}
	}
}

Objective C

#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonHMAC.h>

NSData *hmacForKeyAndData(NSString *key, NSString *data)
{
    const char *cKey  = [key cStringUsingEncoding:NSASCIIStringEncoding];
    const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];
    unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
    CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
    return [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
}

// http://stackoverflow.com/a/9084784
NSString *hexadecimalString(NSData *data){
    /* Returns hexadecimal string of NSData. Empty string if data is empty.   */

    const unsigned char *dataBuffer = (const unsigned char *)[data bytes];

    if (!dataBuffer)
        return [NSString string];

    NSUInteger          dataLength  = [data length];
    NSMutableString     *hexString  = [NSMutableString stringWithCapacity:(dataLength * 2)];

    for (int i = 0; i < dataLength; ++i)
        [hexString appendString:[NSString stringWithFormat:@"%02lx", (unsigned long)dataBuffer[i]]];

    return [NSString stringWithString:hexString];
}
int main (int argc, const char * argv[])
{
    @autoreleasepool {
        NSLog(@"%@", hexadecimalString(hmacForKeyAndData(@"secret", @"Message")));
    }
    return 0;
}

Go

package main

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "fmt"
)

func ComputeHmac256(message string, secret string) string {
    key := []byte(secret)
    h := hmac.New(sha256.New, key)
    h.Write([]byte(message))
    return hex.EncodeToString(h.Sum(nil))
}

func main() {
    fmt.Println(ComputeHmac256("Message", "secret")) // aa747c502a898200f9e4fa21bac68136f886a0e27aec70ba06daf2e2a5cb5597
}

Ruby

require 'openssl'

OpenSSL::HMAC.hexdigest('sha256', "secret", "Message") # aa747c502a898200f9e4fa21bac68136f886a0e27aec70ba06daf2e2a5cb5597

Python (2.x)

import hashlib
import hmac

KEY = "secret"
MESSAGE = "Message"
result = hmac.new(KEY, MESSAGE, hashlib.sha256).hexdigest()
print result # aa747c502a898200f9e4fa21bac68136f886a0e27aec70ba06daf2e2a5cb5597

Python (3.x)

import hashlib
import hmac

KEY = "secret"
KEY_BYTES=KEY.encode('ascii')
MESSAGE = "Message"
MESSAGE_BYTES=MESSAGE.encode('ascii')
result = hmac.new(KEY_BYTES, MESSAGE_BYTES, hashlib.sha256).hexdigest()

print (result) # aa747c502a898200f9e4fa21bac68136f886a0e27aec70ba06daf2e2a5cb5597

Perl

use Digest::SHA qw(hmac_sha256_hex);
$digest = hmac_sha256_hex("Message", "secret");
print $digest; # aa747c502a898200f9e4fa21bac68136f886a0e27aec70ba06daf2e2a5cb5597

Swift

// Add
// #import <CommonCrypto/CommonHMAC.h>
// to the bridging Objective-C bridging header.

import Foundation

enum CryptoAlgorithm {
    case MD5, SHA1, SHA224, SHA256, SHA384, SHA512

    var HMACAlgorithm: CCHmacAlgorithm {
        var result: Int = 0
        switch self {
        case .MD5:      result = kCCHmacAlgMD5
        case .SHA1:     result = kCCHmacAlgSHA1
        case .SHA224:   result = kCCHmacAlgSHA224
        case .SHA256:   result = kCCHmacAlgSHA256
        case .SHA384:   result = kCCHmacAlgSHA384
        case .SHA512:   result = kCCHmacAlgSHA512
        }
        return CCHmacAlgorithm(result)
    }

    var digestLength: Int {
        var result: Int32 = 0
        switch self {
        case .MD5:      result = CC_MD5_DIGEST_LENGTH
        case .SHA1:     result = CC_SHA1_DIGEST_LENGTH
        case .SHA224:   result = CC_SHA224_DIGEST_LENGTH
        case .SHA256:   result = CC_SHA256_DIGEST_LENGTH
        case .SHA384:   result = CC_SHA384_DIGEST_LENGTH
        case .SHA512:   result = CC_SHA512_DIGEST_LENGTH
        }
        return Int(result)
    }
}

extension String {

    func hmac(algorithm: CryptoAlgorithm, key: String) -> String {
        let str = self.cStringUsingEncoding(NSUTF8StringEncoding)
        let strLen = Int(self.lengthOfBytesUsingEncoding(NSUTF8StringEncoding))
        let digestLen = algorithm.digestLength
        let result = UnsafeMutablePointer<CUnsignedChar>.alloc(digestLen)
        let keyStr = key.cStringUsingEncoding(NSUTF8StringEncoding)
        let keyLen = Int(key.lengthOfBytesUsingEncoding(NSUTF8StringEncoding))

        CCHmac(algorithm.HMACAlgorithm, keyStr!, keyLen, str!, strLen, result)

        let digest = stringFromResult(result, length: digestLen)

        result.dealloc(digestLen)

        return digest
    }

    private func stringFromResult(result: UnsafeMutablePointer<CUnsignedChar>, length: Int) -> String {
        var hash = NSMutableString()
        for i in 0..<length {
            hash.appendFormat("%02x", result[i])
        }
        return String(hash)
    }

}


print("Message".hmac(CryptoAlgorithm.SHA256, key: "secret")) //aa747c502a898200f9e4fa21bac68136f886a0e27aec70ba06daf2e2a5cb5597
@beastawakens

This comment has been minimized.

Copy link

@beastawakens beastawakens commented May 5, 2016

Bash

echo -n "your_user_data" | openssl dgst -sha256 -hmac "your API secret"

@mike-north

This comment has been minimized.

Copy link

@mike-north mike-north commented May 30, 2016

New CDN tags for javascript assets. Google ones don't work anymore

<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/hmac-sha256.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/components/enc-base64-min.js"></script>
@mike-north

This comment has been minimized.

Copy link

@mike-north mike-north commented May 30, 2016

Elixir

hmac_digest = :sha256
|> :crypto.hmac(intercom_secure_key, user.intercom_id)
|> Base.encode16
|> String.downcase
@gawin

This comment has been minimized.

Copy link

@gawin gawin commented Jun 6, 2016

Lua

local crypto = require("crypto")
local hmac = require("crypto.hmac")

local result = hmac.digest("sha256", "Intercom.user_id", "Intercom.secret_key")

Note that you need to have LuaCrypto and OpenSSL installed. Install via LuaRocks:
luarocks install luacrypto

@botekchristophe

This comment has been minimized.

Copy link

@botekchristophe botekchristophe commented Jun 21, 2016

Scala

import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec

def encryptSHA256(message: String, secret: String): String = {
    val sha256_HMAC = Mac.getInstance("HmacSHA256")
    val secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256")
    sha256_HMAC.init(secret_key)
    sha256_HMAC.doFinal(message.getBytes())
      .map("%02X" format _)
      .mkString
  }
@AshleyPinner

This comment has been minimized.

Copy link

@AshleyPinner AshleyPinner commented Jul 7, 2016

FYI, the PHP example can be done more simply as:

<?php
echo hash_hmac('sha256', 'Message', 'secret');
?>

If you don't specify the final argument, it defaults to false and outputs as lowercase hexits, as per the docs

@hawkz

This comment has been minimized.

Copy link

@hawkz hawkz commented Aug 12, 2016

Django

Create a template tag:

import hashlib as h 
import hmac as h2

@register.filter(name='hmac')
def hmac(userid, key): 
    """Return the encrypted key"""
    return h2.new(str(key), str(userid), digestmod=h.sha256).hexdigest()

In your template do something like:

{% load your_template_tag_here %}

<script> 
{% if not user.is_authenticated %} 
    window.intercomSettings = { 
      app_id: "XXXXXXXX" 
    }; 
{% else %} 
    window.intercomSettings = { 
      app_id: "XXXXXXXX", 
      name: "{{ request.user.get_full_name }}", // Full name 
      user_id: "{{ request.user.id }}", // User ID 
      created_at: {{ request.user.date_joined|date:"U" }}, // Signup date as a Unix timestamp 
      user_hash: "{{ request.user.id|hmac:'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' }}" 
    }; 
{% endif %} 
</script> 
@sachins

This comment has been minimized.

Copy link

@sachins sachins commented Aug 31, 2016

The Java example works for Android, but make sure to lowercase the result. So result.append(String.format("%02X", b)); should be result.append(String.format("%02x", b));

@atskimura

This comment has been minimized.

Copy link

@atskimura atskimura commented Oct 21, 2016

Apex

String userId = 'userid';
String intercomSecret = 'intercom_secret';
Blob userHashBlob = crypto.generateMac('HmacSHA256', Blob.valueOf(userId), Blob.valueOf(intercomSecret));
String userHash = EncodingUtil.convertToHex(userHashBlob);
@scottsouthard

This comment has been minimized.

Copy link

@scottsouthard scottsouthard commented Feb 26, 2017

Liquid

{% assign my_secret_string = "user_id" | hmac_sha256: "secret_key" %}
My encoded string is: {{ my_secret_string }}
@hasmMarques

This comment has been minimized.

Copy link

@hasmMarques hasmMarques commented Sep 28, 2017

Hi,
Here string CreateToken(string message, string secret)
what means the 'secret' input parameter? it's the apikey?
Cheers,
Hasm

@whitecaps

This comment has been minimized.

Copy link

@whitecaps whitecaps commented Nov 6, 2017

@hasmMarques The secret argument in this case refers to the "Identity Verification Secret" found in your "App Settings" > "Identity verification" page.

@thevalyreangroup

This comment has been minimized.

Copy link

@thevalyreangroup thevalyreangroup commented Jan 12, 2018

Update for Swift 4 and also returns the string in lower case for API satisfaction.

import Foundation

enum CryptoAlgorithm {
    case MD5, SHA1, SHA224, SHA256, SHA384, SHA512
    
    var HMACAlgorithm: CCHmacAlgorithm {
        var result: Int = 0
        switch self {
        case .MD5:      result = kCCHmacAlgMD5
        case .SHA1:     result = kCCHmacAlgSHA1
        case .SHA224:   result = kCCHmacAlgSHA224
        case .SHA256:   result = kCCHmacAlgSHA256
        case .SHA384:   result = kCCHmacAlgSHA384
        case .SHA512:   result = kCCHmacAlgSHA512
        }
        return CCHmacAlgorithm(result)
    }
    
    var digestLength: Int {
        var result: Int32 = 0
        switch self {
        case .MD5:      result = CC_MD5_DIGEST_LENGTH
        case .SHA1:     result = CC_SHA1_DIGEST_LENGTH
        case .SHA224:   result = CC_SHA224_DIGEST_LENGTH
        case .SHA256:   result = CC_SHA256_DIGEST_LENGTH
        case .SHA384:   result = CC_SHA384_DIGEST_LENGTH
        case .SHA512:   result = CC_SHA512_DIGEST_LENGTH
        }
        return Int(result)
    }
}

extension String {
    
    func hmac(algorithm: CryptoAlgorithm, key: String) -> String {
        let str = self.cString(using: String.Encoding.utf8)
        let strLen = Int(self.lengthOfBytes(using: String.Encoding.utf8))
        let digestLen = algorithm.digestLength
        let result = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen)
        let keyStr = key.cString(using: String.Encoding.utf8)
        let keyLen = Int(key.lengthOfBytes(using: String.Encoding.utf8))
        
        CCHmac(algorithm.HMACAlgorithm, keyStr!, keyLen, str!, strLen, result)
        
        let digest = stringFromResult(result: result, length: digestLen)
        
        result.deallocate(capacity: digestLen)
        
        return digest
    }
    
    private func stringFromResult(result: UnsafeMutablePointer<CUnsignedChar>, length: Int) -> String {
        let hash = NSMutableString()
        for i in 0..<length {
            hash.appendFormat("%02x", result[i])
        }
        return String(hash).lowercased()
    }
}
@wmonk

This comment has been minimized.

Copy link

@wmonk wmonk commented Mar 11, 2019

Rust

Translated from our existing python code. The key here was stringifying the uuid before signing it. As Uuid::as_bytes gives a different output to the string version.

use ring::{hmac, digest};
use hex;
use uuid;

let id = uuid::Uuid::new_v4();
let signing_key = hmac::SigningKey::new(
    &digest::SHA256,
    &INTERCOM_KEY.as_bytes()
);
let signed_user_id = hmac::sign(
    &signing_key,
    id.to_string().as_bytes()
);
let intercom_hash = hex::encode(
    signed_user_id.as_ref()
);
@perchrh

This comment has been minimized.

Copy link

@perchrh perchrh commented Nov 26, 2019

Kotlin

The secret parameter is the key received from Intercom, and message is the userId to be hashed.

import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec

object IntercomIdentifyHasher {

    fun createHash(secret: String, message: String): String {
        val algorithm = Mac.getInstance("HmacSHA256")
        val secretKey = SecretKeySpec(secret.toByteArray(), "HmacSHA256")
        algorithm.init(secretKey)

        val hash = algorithm.doFinal(message.toByteArray())
        val result = StringBuffer()
        for (b in hash) {
            result.append(String.format("%02x", b))
        }
        return result.toString()
    }
}
@ermirbeqiraj

This comment has been minimized.

Copy link

@ermirbeqiraj ermirbeqiraj commented Feb 18, 2020

C# snipped needs .ToString("x2") instead of .ToString("X2")

@thewheat

This comment has been minimized.

Copy link
Owner Author

@thewheat thewheat commented Feb 19, 2020

Thanks @ermirbeqiraj I've updated it 👍

@raaowx

This comment has been minimized.

Copy link

@raaowx raaowx commented Jun 17, 2020

Update for Swift 5

Update for Swift 4 and also returns the string in lower case for API satisfaction.

import Foundation
import CommonCrypto.CommonHMAC // !! ADDED

enum CryptoAlgorithm {
    case MD5, SHA1, SHA224, SHA256, SHA384, SHA512
    
    var HMACAlgorithm: CCHmacAlgorithm {
        var result: Int = 0
        switch self {
        case .MD5:      result = kCCHmacAlgMD5
        case .SHA1:     result = kCCHmacAlgSHA1
        case .SHA224:   result = kCCHmacAlgSHA224
        case .SHA256:   result = kCCHmacAlgSHA256
        case .SHA384:   result = kCCHmacAlgSHA384
        case .SHA512:   result = kCCHmacAlgSHA512
        }
        return CCHmacAlgorithm(result)
    }
    
    var digestLength: Int {
        var result: Int32 = 0
        switch self {
        case .MD5:      result = CC_MD5_DIGEST_LENGTH
        case .SHA1:     result = CC_SHA1_DIGEST_LENGTH
        case .SHA224:   result = CC_SHA224_DIGEST_LENGTH
        case .SHA256:   result = CC_SHA256_DIGEST_LENGTH
        case .SHA384:   result = CC_SHA384_DIGEST_LENGTH
        case .SHA512:   result = CC_SHA512_DIGEST_LENGTH
        }
        return Int(result)
    }
}

extension String {
    
    func hmac(algorithm: CryptoAlgorithm, key: String) -> String {
        let str = self.cString(using: String.Encoding.utf8)
        let strLen = Int(self.lengthOfBytes(using: String.Encoding.utf8))
        let digestLen = algorithm.digestLength
        let result = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen)
        let keyStr = key.cString(using: String.Encoding.utf8)
        let keyLen = Int(key.lengthOfBytes(using: String.Encoding.utf8))
        
        CCHmac(algorithm.HMACAlgorithm, keyStr!, keyLen, str!, strLen, result)
        
        let digest = stringFromResult(result: result, length: digestLen)
        
        result.deallocate() // !! UPDATED: Error: deallocate(capacity:)' is unavailable: Swift currently only supports freeing entire heap blocks, use deallocate() instead
        
        return digest
    }
    
    private func stringFromResult(result: UnsafeMutablePointer<CUnsignedChar>, length: Int) -> String {
        let hash = NSMutableString()
        for i in 0..<length {
            hash.appendFormat("%02x", result[i])
        }
        return String(hash).lowercased()
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.