Last active
February 18, 2022 10:19
-
-
Save drovani/df732f165d9735ad635707db1020d55d to your computer and use it in GitHub Desktop.
Sample C# Code to Generate Shopify Multipass Url
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
string secret = "[shopify-multipass-secret]"; | |
string store = "[shopify-store]"; | |
var json = System.Text.Json.JsonSerializer.Serialize(new { | |
email = "[customer-email]", | |
created_at = DateTime.Now.ToString("O"), | |
identifier = "[customer-uid]", | |
//remote_ip = "" | |
}); | |
var hash = System.Security.Cryptography.SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(secret)); | |
var encryptionKey = new ArraySegment<byte>(hash, 0, 16).ToArray(); | |
var signatureKey = new ArraySegment<byte>(hash, 16, 16).ToArray(); | |
var initvector = new byte[16]; | |
new System.Security.Cryptography.RNGCryptoServiceProvider().GetBytes(initvector); | |
byte[] cipherData = new Func<byte[], byte[], byte[]>((iv, key) => | |
{ | |
byte[] encrypted; | |
using (var aes = System.Security.Cryptography.Aes.Create()) | |
{ | |
aes.Key = encryptionKey; | |
aes.IV = iv; | |
aes.Mode = System.Security.Cryptography.CipherMode.CBC; | |
var encryptor = aes.CreateEncryptor(aes.Key, aes.IV); | |
using (MemoryStream ms = new MemoryStream()) | |
using (System.Security.Cryptography.CryptoStream cs = new System.Security.Cryptography.CryptoStream(ms, encryptor, System.Security.Cryptography.CryptoStreamMode.Write)) | |
{ | |
using (StreamWriter sw = new StreamWriter(cs)) | |
{ | |
sw.Write(json); | |
} | |
encrypted = ms.ToArray(); | |
} | |
} | |
return encrypted; | |
})(initvector, encryptionKey); | |
byte[] cipher = initvector.Concat(cipherData).ToArray(); | |
byte[] signature = new HMACSHA256(signatureKey).ComputeHash(cipher); | |
string token = Convert.ToBase64String(cipher.Concat(signature).ToArray()).Replace("+", "-").Replace("/", "_"); | |
string url = $"https://{store}.myshopify.com/account/login/multipass/{token}"; |
Thanks again for taking the time to explain your code. It really boggles my mind how inadequate and full of traps Shopify’s API documentation and development experience are. There are no shortage of questions on their community forum, but without answers to many of them it’s counterproductive. Your code makes sense now, and had you not posted this I would have probably given up.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Garbage collection is a complicated topic, akin to cache invalidation. There's no perfect solution, everyone has an opinion, and nothing works universally.
Having said that, unless you have large, long-running applications, chances are that you'll never really need to worry about the intricacies of GC methodologies. When an app closes, garbage collection will typically clear up everything you forgot to dispose.
Wrapping an
IDisposable
in ausing
statement is a good practice with little downside. Assuming the class implementsIDisposable
according to best practice, the objects will all get disposed during the finalizer.More about that can be found at CA1063: Implement IDisposable correctly.