<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Zakaria El Asri</title>
    <description>The latest articles on DEV Community by Zakaria El Asri (@zakariaelas).</description>
    <link>https://dev.to/zakariaelas</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F720514%2Fd34b767f-f2b9-4a4c-b56a-049f26c65bf6.jpeg</url>
      <title>DEV Community: Zakaria El Asri</title>
      <link>https://dev.to/zakariaelas</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zakariaelas"/>
    <language>en</language>
    <item>
      <title>Demystifying TLS</title>
      <dc:creator>Zakaria El Asri</dc:creator>
      <pubDate>Tue, 23 Nov 2021 20:51:58 +0000</pubDate>
      <link>https://dev.to/zakariaelas/demystifying-tls-3plm</link>
      <guid>https://dev.to/zakariaelas/demystifying-tls-3plm</guid>
      <description>&lt;p&gt;I recently had to prepare a presentation on TLS as part of the cybersecurity class I was taking. Researching and understanding TLS took quite some effort. However, I was quite satisfied with the things I had learned. In this blog post, I wanted to document the things I understood, as well as try to answer some of the questions I asked myself while preparing my presentation.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Before reading, I strongly recommend you read a little about asymmetric/symmetric encryption, message authentication code (MAC), and digital certificates. I don't believe you need extensive background in those topics, but exposure will definitely help. I am personally not an expert in any of those topics and doubt i'd be able to do a better job than what's already available out there.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's so special about this article?
&lt;/h2&gt;

&lt;p&gt;Not much. All the information you'll find here is already available on the internet. However, it's been a bit challenging for me to compile that information and connect the dots. For me, this article is simply what I wish I found when I was researching the topic. &lt;/p&gt;

&lt;h2&gt;
  
  
  Motivation of TLS
&lt;/h2&gt;

&lt;p&gt;Before talking about what Transport Layer Security (TLS) is, let's briefly introduce why it exists in the first place. The overarching objective is to set up a secure communication channel over internet which guarantees confidentiality, integrity, and authenticity. &lt;/p&gt;

&lt;p&gt;TLS tells us &lt;strong&gt;how&lt;/strong&gt; to set up such a secure channel. It tells us the exact steps a client/server should follow to set it up. Concepts such as asymmetric/symmetric encryption, digital signatures, MACs, etc. are our building blocks, and TLS fits them together to achieve its overarching goal. &lt;/p&gt;

&lt;h2&gt;
  
  
  Brief Evolution of TLS
&lt;/h2&gt;

&lt;p&gt;I won't get into much detail here. This is mainly to clear up any confusion between SSL and TLS. People have developed a tendency to use both interchangeably, but the two have significant technical differences. &lt;/p&gt;

&lt;p&gt;First, TLS 1.0 (the first version) deprecated SSL 3.0 (the last SSL version). Both protocols actually work towards the same goal, except that multiple vulnerabilities were discovered in SSL, which logically led to its deprecation. Actually, even the first two iterations of TLS (TLS 1.0 &amp;amp; TLS 1.1) are now considered deprecated. Major browsers have announced lately that they don't plan on supporting them in the future. I found a pretty cool illustration from the &lt;a href="https://www.globalsign.com/en/blog/ssl-vs-tls-difference"&gt;GlobalSign blog&lt;/a&gt; that summarizes the evolution of TLS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--i-4XYOM4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.globalsign.com/application/files/7615/8160/7092/evolution_of_SSL_and_TLS.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i-4XYOM4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.globalsign.com/application/files/7615/8160/7092/evolution_of_SSL_and_TLS.jpg" alt="Evolution of SSL" width="880" height="567"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Relationship with SSL/TLS certificates
&lt;/h3&gt;

&lt;p&gt;This is also one thing I wish to clear up. If SSL and TLS certificates are two different protocols, does that mean that when we acquire an SSL certificate, we have to use SSL and not TLS? Absolutely not. You might (and should) be using TLS, yet certificate registration providers will likely refer to your digital certificate as an SSL certificate. I believe this is just a name that stuck around for the longest time. More providers are starting to use the term SSL/TLS certificate, but it still a little bit confusing. &lt;/p&gt;

&lt;p&gt;The point is: the certificate does &lt;strong&gt;NOT&lt;/strong&gt; determine the protocol. The way everything fits together is that digital certificates are used &lt;strong&gt;WITH&lt;/strong&gt; TLS or SSL. &lt;/p&gt;

&lt;p&gt;TLS or SSL is the protocol. The certificate is just a means to prove the authenticity of the public key and can be used with both TLS and SSL irrespective of what they're being called by others/certificate registration providers. &lt;/p&gt;

&lt;h3&gt;
  
  
  The TLS Protocol
&lt;/h3&gt;

&lt;p&gt;One of the first descriptions of TLS you'll come across is: "TLS is a layered protocol". It is comprised of 2 layers. The first (lower) layer is for the Record Protocol. The second (upper) layer is for one of the following 4 protocols: the handshake protocol, the alert protocol, the change cipher spec protocol, the heartbeat protocol and the application data protocol. &lt;/p&gt;

&lt;p&gt;The Record Protocol, by being the lower layer, abstracts some functionality from the upper layer. It's quite similar to how IP provides a service (e.g. routing, addressing) for TCP and UDP. In the context of TLS, the Record Protocol can fragment, apply a MAC, encrypt, or/and optionally compress data. At the receiving end, it can reassemble, verify, decrypt, or/and optionally decompress data. &lt;/p&gt;

&lt;p&gt;The upper layer protocols are used for different purposes, mainly, negotiating encryption algorithms/secrets and providing some error control. &lt;/p&gt;

&lt;p&gt;The layered approach abstracts behavior and provides services to the upper layer. The motivation behind this layered approach is similar to what you might be familiar with in the case of the TCP/IP and OSI models: modularity, decoupling, re-use, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Terminology
&lt;/h2&gt;

&lt;p&gt;Before talking more detail, I want to introduce some terminology. I think it will help in our discussion and in case you read other more technical articles.&lt;/p&gt;

&lt;p&gt;TLS, as a protocol, exchanges messages and in the context of TLS, we usually call those &lt;strong&gt;records&lt;/strong&gt;. Each record contains a specific set of common fields + some other fields depending on what is used in the upper layer. These "other fields" depend mainly on the value of the content type field (which is found in all TLS records). Below is a representation of a TLS record. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IKgSQ7Xk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a0fm6esz5gerqqueqe5b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IKgSQ7Xk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a0fm6esz5gerqqueqe5b.png" alt="TLS record general format" width="591" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This diagram is abstract. Can you guess why?&lt;/p&gt;

&lt;p&gt;The reason is because the "Payload" on the above diagram doesn't really mean anything... The payload will depend on what the content type field value is. However, the key takeaway here is that every TLS record will have &lt;strong&gt;at least&lt;/strong&gt; the fields specified above. &lt;/p&gt;

&lt;h2&gt;
  
  
  TLS Content Types
&lt;/h2&gt;

&lt;p&gt;As mentioned previously, there are different values for the content type field. Each conforms to a specific 2nd layer protocol. Our focus will be mainly on the first 3, but I thought it would be nice to provide at least a short description for each protocol. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Handshake&lt;/strong&gt;: used to exchange the necessary information required by the client and the server to start encrypting the application data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ChangeCipherSpec&lt;/strong&gt;: used to change the encryption strategy/algorithm being used by the client and server&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application Data&lt;/strong&gt;: used to refer to the messages we get from the application layer (e.g. an HTTP request or response). The messages are carried by the Record Protocol and are basically treated as transparent data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alert&lt;/strong&gt;: used to signal an error or a warning&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Heartbeat&lt;/strong&gt;: used to test and keep alive the secure communication&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, with the background we have acquired, we can go back to the previous TLS record format, and provide some more detail.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ORIxHfc9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aq5l87dnxw5j5chfi4d6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ORIxHfc9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aq5l87dnxw5j5chfi4d6.png" alt="TLS record format for handshake protocol" width="601" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Scroll back up and try to compare the two record structures. &lt;/p&gt;

&lt;p&gt;Note the absence of the abstract "payload". Instead, because this is a handshake record (note the 22 value in the content type field), we have additional fields such as message type and handshake message data length.&lt;/p&gt;

&lt;h2&gt;
  
  
  TLS Handshake
&lt;/h2&gt;

&lt;p&gt;The TLS handshake is the series of TLS records exchanged by a client and a server to establish a secure communication. I enjoyed reading about this topic because it captures how everything fits together. If you ever asked yourself how a TLS session is established when you navigate to &lt;a href="https://google.com"&gt;https://google.com&lt;/a&gt;, this answers it. &lt;/p&gt;

&lt;p&gt;First, we'll briefly talk about the TLS handshake steps, then, at each step, we'll make use of wireshark so that we can see things in practice.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_GB5djXg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eggkxstmzmnikxe2zqg0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_GB5djXg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eggkxstmzmnikxe2zqg0.png" alt="TLS handshake steps" width="651" height="963"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Client Hello
&lt;/h3&gt;

&lt;p&gt;The client initiates the handshake by sending a Client Hello message to the server. The TLS record will include, among other things, the supported TLS versions and a string of random bytes known as the &lt;strong&gt;client random&lt;/strong&gt;. The client random is simply a set of random bytes. We'll see how it is used later. The supported &lt;strong&gt;cipher suite&lt;/strong&gt; is also sent from the client. A cipher suite is just a set of cryptographic algorithms that can be used to encrypt the communication channel. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HJkXWfjW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hlaku6xifyj7fvz54x2m.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HJkXWfjW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hlaku6xifyj7fvz54x2m.jpg" alt="TLS client hello" width="780" height="332"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's take a closer look at the cipher suites field&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yerlxYYp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7wyam9fhkxg7gqbpwd29.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yerlxYYp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7wyam9fhkxg7gqbpwd29.png" alt="Cipher suites" width="831" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We'll take &lt;strong&gt;TLS_RSA_WITH_AES_256_CBC_SHA&lt;/strong&gt; as an example and try to parse it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;RSA&lt;/strong&gt;: Refers to the algorithm used for the key exchange. As we'll see later, our client will generate a premaster secret and will have to send it to the server. The premaster secret is a sensitive piece of information. In order to guarantee its confidentiality, an encryption algorithm needs to be used. If the server chooses the cipher suite we took as an example, it will use RSA to encrypt the premaster secret.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AES_256_CBC&lt;/strong&gt;: Refers to the symmetric-key algorithm used to encrypt the session data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SHA&lt;/strong&gt;: Refers to the MAC algorithm used.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 2: Server Hello
&lt;/h3&gt;

&lt;p&gt;The server will respond with a Server Hello message. It will include the server's chosen cipher and TLS version, as well as a &lt;strong&gt;server random&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---FrD0kUG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/70deqeksuntdqmk6btu0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---FrD0kUG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/70deqeksuntdqmk6btu0.jpg" alt="TLS server hello" width="784" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Server Certificates
&lt;/h3&gt;

&lt;p&gt;The server will send its certificate chain for the client to verify. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CCmdVZoc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2fdoi91np5u499fxn682.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CCmdVZoc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2fdoi91np5u499fxn682.jpg" alt="TLS certificates" width="880" height="216"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Server Hello Done
&lt;/h3&gt;

&lt;p&gt;The server sends this message to signal the completion of the hello-message phase of the handshake. In other words, when a client receives this message, it should know that the server is done sending messages. The client should now verify the server certificate and move on to the next step.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_b1kffPL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lyp5h7q2dfqa1tiov3nc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_b1kffPL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lyp5h7q2dfqa1tiov3nc.png" alt="TLS server hello done" width="734" height="155"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Client Key Exchange
&lt;/h3&gt;

&lt;p&gt;This is the beginning of a new phase, the client key exchange phase. The client will generate one more string of random bytes referred to as the &lt;strong&gt;premaster secret&lt;/strong&gt;. The public key of the server, which the client should have authenticated by verifying the server certificate, is used to encrypt the premaster secret. Only the server should be able to decrypt the premaster secret because only it has the private key. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--voZm-uii--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cdm750qp13xwirda943j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--voZm-uii--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cdm750qp13xwirda943j.png" alt="TLS client key exchange" width="880" height="217"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Key Generation
&lt;/h3&gt;

&lt;p&gt;At this level, both the client and server have enough information to generate session keys. The server random, client random, and premaster secret will be used to generate the session keys. &lt;/p&gt;

&lt;h3&gt;
  
  
  Step 7: Change Cipher Spec Message
&lt;/h3&gt;

&lt;p&gt;This message is sent to instruct the server that subsequent TLS records will use another encryption mode. In this case, we switch from asymmetric to symmetric encryption.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--J8nVB0hq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8ktjca0klj1rbk576ysi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--J8nVB0hq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8ktjca0klj1rbk576ysi.png" alt="TLS CipherSpecMessage" width="821" height="115"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is the CipherSpecMessage part of the CipherSpecProtocol and not a simple message part of the Handshake Protocol?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Think about it. Can't we just include a boolean that says either yes or no for switching the encryption mode as part of some Handshake message?&lt;/p&gt;

&lt;p&gt;I think the answer to these questions boils down to a design decision that was once made when defining the TLS Protocol. Actually, I have not mentioned this previously, but many TLS messages can be batched into one TLS Record, &lt;strong&gt;as long as they belong to the same 2nd layer protocol&lt;/strong&gt;. This means that one or more TLS Handshake messages can be sent as part of one TLS record. The problem is that encryption is performed at the record level! &lt;/p&gt;

&lt;p&gt;Imagine sending a message to the server, saying, "hey, please switch to the new encryption mode", but then, this same message + potentially other messages are encrypted using the &lt;strong&gt;new&lt;/strong&gt; encryption mode .. which the server does NOT expect. &lt;/p&gt;

&lt;p&gt;The fact that the ChangeCipherSpec message is part of its own protocol (the ChangeCipherSpec protocol) breaks this batching. Now implementations are forced to start a new TLS Record when new encryption settings are set! This is particularly relevant in the next step because the subsequent TLS message will now be encrypted using the new settings, and the server would expect that (because it would have received a ChangeCipherSpec message).&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 8: Finished
&lt;/h3&gt;

&lt;p&gt;The finished message is the first message that is encrypted using the newly negotiated algorithms, keys, and secrets. It should be sent right after the ChangeCipherSpec message.&lt;/p&gt;

&lt;p&gt;The receiving end must verify that its contents are correct. In fact, this is quite a crucial step, because it allows the receiving end to verify that the authentication and key exchange processes were successful and not tampered with. Remember, an active man-in-the-middle should be able to tamper with the Client Hello, Server Hello, and other non-encrypted TLS Handshake messages. The Finished message includes a hash over unencrypted handshake messages (e.g. ClientHello, ServerHello). &lt;/p&gt;

&lt;p&gt;When a party receives the Finished message, it decrypts it using the session key, then computes a hash over all the previous handshake messages it received (all are kept up until this point), then it compares this hash with the hash that was sent as part of the Finished message.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DQOhzQtv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/17xane5gsoppp8929h25.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DQOhzQtv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/17xane5gsoppp8929h25.png" alt="TLS Finished message" width="822" height="116"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 9 and 10: Change Cipher Spec and Finished Messages
&lt;/h3&gt;

&lt;p&gt;Similar to steps 7 and 8, except that this is sent from the server to instruct that the messages from the server to the client will use new encryption settings. The Finished message in this case is sent for the client to validate the newly negotiated algorithms, keys, and secrets. &lt;/p&gt;

&lt;p&gt;This is the last step in the Handshake Protocol.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 11: Application Data
&lt;/h3&gt;

&lt;p&gt;Now that the server is authenticated and the encryption algorithm + keys are negotiated, we are ready to start sending and receiving encrypted application-layer data: https in our example.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--d--fv1kl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dhqzbe9v8f94bajr5f9s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--d--fv1kl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dhqzbe9v8f94bajr5f9s.png" alt="TLS application data" width="880" height="120"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conlusion
&lt;/h2&gt;

&lt;p&gt;I hope this has been somewhat helpful. Truth be told, TLS is a new topic for me. I had been exposed to it in the past and have even set up an HTTPS server, but I never really knew the details of how the session key is generated or how digital certificates are sent from the server to the client. &lt;/p&gt;

&lt;p&gt;There is still much to talk about in TLS, but I feel like, for now, this answered most of the questions I had when I first read about the topic. Feel free to zoom in on each part and read more about the various protocols. The goal of this article was to expose you to TLS.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Transport_Layer_Security"&gt;Wikipedia - Transport Layer Security&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.globalsign.com/en/blog/ssl-vs-tls-difference"&gt;SSL vs TLS - What's the Difference?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://datatracker.ietf.org/doc/html/rfc8446"&gt;RFC 8446&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cloudflare.com/learning/ssl/what-happens-in-a-tls-handshake/"&gt;What happens in a TLS handshake? | SSL handshake&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>todayilearned</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>Blazing-fast product search w. MeiliSearch and Medusa</title>
      <dc:creator>Zakaria El Asri</dc:creator>
      <pubDate>Tue, 26 Oct 2021 17:21:47 +0000</pubDate>
      <link>https://dev.to/medusajs/blazing-fast-product-search-w-meilisearch-and-medusa-3dee</link>
      <guid>https://dev.to/medusajs/blazing-fast-product-search-w-meilisearch-and-medusa-3dee</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;Search functionality is one of the most useful and important features in e-commerce platforms. From increasing customer conversion rates to significantly improving the user experience, search engines can enable significant business growth. &lt;a href="https://github.com/medusajs/medusa" rel="noopener noreferrer"&gt;Medusa&lt;/a&gt; brings search functionality to your doorstep by leveraging some of the already existing search engines out there.&lt;/p&gt;

&lt;p&gt;We have developed a plugin that will allow you to use the performant, open-source, and feature-rich search engine MeiliSearch. &lt;/p&gt;

&lt;p&gt;MeiliSearch is a super-fast, open-source, search engine built in Rust. It comes with a wide range of features such as typo-tolerance, filtering, sorting, and &lt;a href="https://docs.meilisearch.com/learn/what_is_meilisearch/features.html" rel="noopener noreferrer"&gt;much more&lt;/a&gt;. MeiliSearch also provides a pleasant developer experience, as it is extremely intuitive and newcomer-friendly - so even if you're new to the search engine "ecosystem", you'll have a great time navigating through their documentation. &lt;/p&gt;

&lt;p&gt;Through Medusa flexible plugin system, it is possible to enable search functionality into your medusa applications with minimum hassle by including our new plugin &lt;code&gt;medusa-plugin-meilisearch&lt;/code&gt; to your &lt;code&gt;medusa-config.js&lt;/code&gt; file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;In case you don't have MeiliSearch installed locally on your environment yet, you can run the following:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Install MeiliSearch&lt;/span&gt;
curl &lt;span class="nt"&gt;-L&lt;/span&gt; https://install.meilisearch.com | sh

&lt;span class="c"&gt;# Launch MeiliSearch&lt;/span&gt;
./meilisearch


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;For other installation alternatives, you can head over to Meilisearch's &lt;a href="https://docs.meilisearch.com/learn/getting_started/installation.html" rel="noopener noreferrer"&gt;installation guide&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;In order to add the plugin to your medusa project, you will need to first install the plugin using your favorite package manager:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# yarn&lt;/span&gt;
yarn add medusa-plugin-meilisearch

&lt;span class="c"&gt;# npm&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;medusa-plugin-meilisearch


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then in your &lt;code&gt;medusa-config.js&lt;/code&gt; file, add the plugin to your &lt;code&gt;plugins&lt;/code&gt; array. For this example, assumption is that you're leveraging MeiliSearch to perform searches on an index called &lt;code&gt;products&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...other options&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="c1"&gt;// ...other plugins&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`medusa-plugin-meilisearch`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// config object passed when creating an instance of the MeiliSearch client&lt;/span&gt;
                &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://127.0.0.1:7700&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your_master_key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="na"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// index name&lt;/span&gt;
                    &lt;span class="na"&gt;products&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="c1"&gt;// MeiliSearch's setting options to be set on a particular index&lt;/span&gt;
                        &lt;span class="na"&gt;searchableAttributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;description&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;variant_sku&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                        &lt;span class="na"&gt;displayedAttributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;description&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;variant_sku&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                    &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Et voilà! That's all it takes to make medusa and MeiliSearch work in great harmony. Please note that you can use any other setting from this &lt;a href="https://docs.meilisearch.com/reference/features/settings.html#settings" rel="noopener noreferrer"&gt;list&lt;/a&gt; such as &lt;code&gt;filterableAttributes&lt;/code&gt;, &lt;code&gt;sortableAttributes&lt;/code&gt;, and &lt;code&gt;synonyms&lt;/code&gt;. We are working on another blog post that will demonstrate how you can make use of these settings to build a great storefront experience, so stay tuned to that!&lt;/p&gt;

&lt;h3&gt;
  
  
  Simple Usage
&lt;/h3&gt;

&lt;p&gt;Medusa exposes an API layer that can serve as an abstraction over various search providers. We will now be interacting with one of the search routes parts of that layer, namely, the &lt;code&gt;POST /store/products/search&lt;/code&gt; route. The route will enable you to test out the integration between Medusa and MeiliSearch. The endpoint takes a mandatory &lt;code&gt;q&lt;/code&gt; property and a set of optional parameters which will be passed to MeiliSearch's &lt;code&gt;search()&lt;/code&gt; method as a second argument. The list of the parameters which can be provided can be found in MeiliSearch's &lt;a href="https://docs.meilisearch.com/reference/api/search.html#search-in-an-index-with-post-route" rel="noopener noreferrer"&gt;docs&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Let's use Postman for this short demo to get some search results:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feym0vmmw55h4wafz0hgp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feym0vmmw55h4wafz0hgp.png" alt="Postman screenshot showing search request and response"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We tried to perform a search query "creneck" to find all crewnecks in our store. Note how the explicit mistake of leaving a "w" out from "crewneck" still yields the correct results.&lt;/p&gt;

&lt;p&gt;Postman is not the most exciting client to use to showcase this, so in the next section, there is a short guide on how you can use React and MeiliSearchh's ecosystem to build something that looks better than JSON.&lt;/p&gt;

&lt;h3&gt;
  
  
  Highlighting and Pagination in a React Storefront
&lt;/h3&gt;

&lt;p&gt;The Medusa + MeiliSearch integration opens up a lot of capabilities for creating a rich UX for your storefront. The plugin indexes all your products and listens to any updates made on them, so you can then leverage any client-side SDKs developed by the MeiliSearch team to build cool search experiences for storefronts. For example, MeiliSearch exposes a React &lt;a href="https://github.com/meilisearch/meilisearch-react/" rel="noopener noreferrer"&gt;adapter&lt;/a&gt; that can be used with React InstantSearch (made by Algolia) which provides features such as highlighting, filtering, and pagination out of the box. &lt;/p&gt;

&lt;p&gt;In order to leverage this functionality, you'll need to install the corresponding packages by running:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# npm&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;react-instantsearch-dom @meilisearch/instant-meilisearch
&lt;span class="c"&gt;# yarn&lt;/span&gt;
yarn add react-instantsearch-dom @meilisearch/instant-meilisearch


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can then use the MeiliSearch client in your react app:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;InstantSearch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Hits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;SearchBox&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Pagination&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Highlight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-instantsearch-dom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;instantMeiliSearch&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@meilisearch/instant-meilisearch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;instantMeiliSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://127.0.0.1:7700&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your_master_key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SearchPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;InstantSearch&lt;/span&gt;
    &lt;span class="na"&gt;indexName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"products"&lt;/span&gt;
    &lt;span class="na"&gt;searchClient&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;searchClient&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SearchBox&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Hits&lt;/span&gt; &lt;span class="na"&gt;hitComponent&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Hit&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Pagination&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;InstantSearch&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Hit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;hit&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"hit-name"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Highlight&lt;/span&gt; &lt;span class="na"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hit&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;align&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"left"&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"hit-description"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Snippet&lt;/span&gt; &lt;span class="na"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt; &lt;span class="na"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hit&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"hit-info"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;price: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"hit-info"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;release date: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;releaseDate&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If you want to play around with the various features provided by React InstantSearch you can read more on algolia's &lt;a href="https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;. You can also use MeiliSearch's react &lt;a href="https://codesandbox.io/s/ms-react-is-sh9ud?fontsize=14&amp;amp;hidenavigation=1&amp;amp;theme=dark&amp;amp;file=/src/App.js" rel="noopener noreferrer"&gt;demo&lt;/a&gt; for a more interactive example.&lt;/p&gt;

&lt;h3&gt;
  
  
  Demo: Palmes Storefront
&lt;/h3&gt;

&lt;p&gt;By using the above libraries (React, &lt;code&gt;react-instantsearch-dom&lt;/code&gt;, and &lt;code&gt;instant-meilisearch&lt;/code&gt;) in addition to the medusa plugin, we have successfully integrated the MeiliSearch plugin for one of our customers: &lt;a href="https://palmes.co" rel="noopener noreferrer"&gt;Palmes&lt;/a&gt;. Following is a short GIF demoing the functionality. &lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/639184340" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Enhance your development experience with MeiliSearch's Web UI
&lt;/h3&gt;

&lt;p&gt;For a quicker feedback loop on what's happening on your search engine, you can use MeiliSearch's helpful out-of-the-box web interface to run some searches and get live results. It comes with MeiliSearch when you first install it and requires 0 configuration. When integrating the MeiliSearch plugin to existing medusa projects, we also found it to be extremely helpful for debugging&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/639186298" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  More to come
&lt;/h3&gt;

&lt;p&gt;As briefly mentioned before, we're preparing another blog post that dives a bit deeper into the Medusa Search API and provides a more in-depth walkthrough on how to build a feature-rich search experience that includes filtering, synonyms, stop-words, and more!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>javascript</category>
      <category>headless</category>
      <category>ecommerce</category>
    </item>
  </channel>
</rss>
