Securing your Flow integration
How to take the next step and ensure your Flow is secure
The code we've written so far is for helping you try out Flow in your app quickly, but to deploy Flow live to your customers you need to cryptographically sign the customer_reference
field using your API secret.
NOTE: Without signing the customer_reference
field, your Flow integration will stop working after you've created 100 Flow sessions.
Signing your Customer Reference
To access your API secret, visit the "API Keys" tab in the integration settings modal you used earlier.
Using your API secret in the backend part of your application, create a Base64 encoded SHA-256 HMAC signature of the user identifier that you're passing to the customerReference
field for Flow.
We realize that's a mouthful, so for example, imagine we are using these values for our integration:
- Our customer's id is the UUID value
3a409367-a417-4d46-9a92-3d7bc5dc4605
- Our API secret is
live_secret_abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234
The correct signature for these values would be yw0hqBPOIWcHPFZBsaMPnxktOrWwWkZcWP+TneV5D48=
.
TIP: Try confirming that your signature function outputs the same value as the example above before you move on to using real customer ids with your actual secret!
In Ruby, we would compute the signature with this code:
require 'openssl'
require 'base64'
def sign_customer_reference(api_secret:, customer_reference:)
digest =
OpenSSL::HMAC.digest(
OpenSSL::Digest.new('SHA256'),
api_secret,
customer_reference
)
return Base64.strict_encode64(digest)
end
signature = sign_customer_reference(
api_secret: 'live_secret_abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234',
customer_reference: "3a409367-a417-4d46-9a92-3d7bc5dc4605"
)
puts signature # => yw0hqBPOIWcHPFZBsaMPnxktOrWwWkZcWP+TneV5D48=
If you need help generating your signature, please feel free to email support@cognitohq.com
Providing your signature to Flow
Once you've got your customer referencing signing code implemented, we can shift our focus back to the frontend. You should now update your Flow initialization code to look like this:
<script src="https://cdn.cognitohq.com/flow.js"></script>
<script type="text/javascript">
const flow = new Flow({
publishableKey: "live_publishable_key_11111111111111111111111111111111",
templateId: "flwtmp_11111111111111",
user: {
customerReference: currentUser.id,
email: currentUser.email,
signature: currentUser.flowSignature
}
});
</script>
where currentUser.flowSignature
is the value of the signature computed using your API secret and currentUser.id
.
Once you've updated your code, try launching Flow again like you did before we added signature. If your signature is correct, the Flow modal should open like it did before. If it doesn't, check the browser's developer console for error messages. Flow will log to console.error
if it detect an integration issue like an invalid signature.
Security checklist for signed requests
Before you go move on, review this checklist to make sure you're keeping your users secure
Flow signatures should only be computed on your backend.
Your application's backend should compute the Flow signature, then serve it to your frontend. Computing the signature on the frontend would expose your API secret to the world, giving anyone the ability to access all of the sensitive data associated with your Cognito account. If we detect API secrets exposed in insecure settings, we will immediately revoke the keys, which will break your integration.
Your users should not be able to generate signatures for anything besides their own id.
How you serve the signature from your backend is up to you. One approach would be to compute the signature on each page load using the current user's id and render it directly into the page. Another approach might be to implement an internal API endpoint like
/api/users/current/flow_signature
which computes the signature based on the user id associated with the current users session.An insecure approach would be providing an internal API endpoint like
/api/compute_signature
which accepts a value for the backend to sign. This is insecure for the similar reasons to the first checklist item. An attacker could easily send many different values to this endpoint and create unique Flow sessions with them in order to subvert the compliance and anti-fraud checks Flow provides you.Your
customer_reference
must be unique and persistent per-userCognito uses the
customer_reference
to enforce that each of your customers can only complete their Flow once unless you authorize retries. If thecustomer_reference
you provide for a user in your system changes, Cognito cannot enforce this access control. You can read more about how thecustomer_reference
is critical for your integration working properly and securely in the customer references section.Your API secret should loaded into your application securely, and you should share it with as few employees as possible
In our code example above, we hardcoded the API secret for the sake of simplicity. In a real application, your API secret should be set as an environment variable on your production servers. For your development machines, you can use your Playground API Keys. When configuring your development machines, make sure a publishable key and template id from our playground environment
Requiring signed requests
Once you've verified that customer signatures are working with your application, you need to configure your Flow integration to only accept signed requests. You can enable this by visiting the Flow dashboard, opening the Integration Settings for your Flow template, selecting the "Going Live" tab, and toggling the setting for "Require Signed Requests."
NOTE: Your Flow integration will stop working after you've created 100 Flow sessions unless you have enabled "Require Signed Requests."
Security Checklist
To sanity check that you've secured your integration, please review this checklist before going live:
- You've read the security checklist for signing customer signatures
- The value you're providing to
customerReference
is unique and persistent for each user - Your webhook receiver makes sure to check the signature of each request before processing the data
- Your domain whitelist settings contain only the domains you intend to use Flow on, and you've removed any temporary servers (like ngrok) once you're done using them
- You've added signed customer references to your integration, and understand that the API will stop working after 100 Flow sessions if you haven't enabled the "Require Signed Requests" setting