Protocol between Frontend and Backend
-
Frontend and Backend using the same key
Example:
key = 'cdbdb4ff58e66858cba67787312e2e324c4b217e48680d443a42d96496556834ab549f199b5081d2926e644398e6408ba9ed72d96b1119fc7d4474938ee7c0f7'; -
The signature that Frontend send to Backend have format:
"#{base64_encoded_timestamp}--#{sha256 hash}" -
In Frontend
-
The signature can be created by code: (test it here https://codesandbox.io/s/0oyv4wmrow)
var HmacSHA256 = require("crypto-js/hmac-sha256"); var time = new Date().getTime() / 1000; var base64_encoded_timestamp = btoa(time); var key = "cdbdb4ff58e66858cba67787312e2e324c4b217e48680d443a42d96496556834ab549f199b5081d2926e644398e6408ba9ed72d96b1119fc7d4474938ee7c0f7"; var sha256_hash = HmacSHA256(base64_encoded_timestamp, key); var signature = base64_encoded_timestamp + "--" + sha256_hash; document.getElementById("app").innerHTML = signature;
-
Send the request to Backend
signature=[$base64_encoded_timestamp]--[$sha256_hash] -
In Backend
- Backend get the params[signature] to verify.
- First step is getting the time (using '--' as separator), decode it and compare the time to the Time.now.utc in server. If the different between 2 times is less than 2 minutes, process next step. Otherwise, return { success: false, message: 'Invalid Timestamp' }.
- Next step is using key to verify the signature. If fail, return { success: false, message: 'Invalid Signature' }.
- If the request passes 2 steps above, it's a valid request and the API will return approriate data.
def verify_signature(signature) secret = 'cdbdb4ff58e66858cba67787312e2e324c4b217e48680d443a42d96496556834ab549f199b5081d2926e644398e6408ba9ed72d96b1119fc7d4474938ee7c0f7' verifier = ActiveSupport::MessageVerifier.new(secret, serializer: JSON, digest: "SHA256") sig = signature time = Base64.decode64(sig.split('--').first).to_i rescue nil if time && (Time.now.utc.to_i - time.to_i < 2.minutes) verifier.verify(signature) return {success: true} else puts 'Invalid Timestamp' return { success: false, message: 'Invalid Timestamp', status: "error" } end rescue ActiveSupport::MessageVerifier::InvalidSignature puts 'Invalid Signature' return { success: false, message: 'Invalid Signature', status: "error" } end