<?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: Sébastien Pertus</title>
    <description>The latest articles on DEV Community by Sébastien Pertus (@mimetis).</description>
    <link>https://dev.to/mimetis</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%2F40324%2F73421975-2caf-41a3-9d28-2de1f2909408.jpeg</url>
      <title>DEV Community: Sébastien Pertus</title>
      <link>https://dev.to/mimetis</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mimetis"/>
    <language>en</language>
    <item>
      <title>How to Secure Your TanStack React Start App with Light-Auth</title>
      <dc:creator>Sébastien Pertus</dc:creator>
      <pubDate>Wed, 20 Aug 2025 14:47:42 +0000</pubDate>
      <link>https://dev.to/mimetis/how-to-secure-your-tanstack-react-start-app-with-light-auth-12o0</link>
      <guid>https://dev.to/mimetis/how-to-secure-your-tanstack-react-start-app-with-light-auth-12o0</guid>
      <description>&lt;p&gt;&lt;a href="https://lightauth.github.io" rel="noopener noreferrer"&gt;Light-Auth&lt;/a&gt; is a lightweight authentication solution designed for simplicity and ease of integration. &lt;br&gt;
It provides essential authentication features with minimal setup, making it ideal for &lt;strong&gt;React developers&lt;/strong&gt;, &lt;strong&gt;prototypes&lt;/strong&gt;, and &lt;strong&gt;SSR frameworks&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You can find an introduction to &lt;a href="https://lightauth.github.io" rel="noopener noreferrer"&gt;Light-Auth&lt;/a&gt; here: &lt;a href="https://dev.to/mimetis/light-auth-a-lightweight-auth-sdk-for-ssr-frameworks-9o8"&gt;Light-Auth: Authentication for SSR Frameworks&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  ✅ Why Use Light-Auth?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quick Setup&lt;/strong&gt;: Minimal configuration required.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supports OAuth Providers&lt;/strong&gt;: Google, GitHub, and more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lightweight&lt;/strong&gt;: Minimal dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensible&lt;/strong&gt;: Easily customize for advanced use cases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Works Everywhere&lt;/strong&gt;: Compatible with SSR frameworks like Next.js, Astro, SvelteKit, Nuxt, and TanStack Start.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  🔐 How to Use Light-Auth with TanStack Start
&lt;/h2&gt;

&lt;p&gt;This guide walks you through the steps to add authentication and authorization to your Tanstack Start application using Light-Auth.&lt;/p&gt;

&lt;p&gt;👉 You can find the complete code for a sample Tanstack Start application here: &lt;a href="https://github.com/lightauth/light-auth-tanstack-sample-one" rel="noopener noreferrer"&gt;Tanstack Start Sample with Light-Auth&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  1) Install Light-Auth
&lt;/h3&gt;

&lt;p&gt;Once you have created your Tanstack Start application (you can follow this tutorial: &lt;a href="https://tanstack.com/start/latest/docs/framework/react/build-from-scratch" rel="noopener noreferrer"&gt;Tanstack Start Build from Scratch&lt;/a&gt;), you can add Light-Auth for Tanstack using your preferred package manager:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nt"&gt;-i&lt;/span&gt; @light-auth/tanstack-react-start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2) Add your OAUTH providers
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Light-Auth&lt;/strong&gt; uses &lt;strong&gt;Arctic providers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You will find the complete list of Arctic providers on the official website: &lt;a href="https://arcticjs.dev/" rel="noopener noreferrer"&gt;Arctic v3&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each provider needs to be configure, usually with a &lt;code&gt;ClientId&lt;/code&gt;, a &lt;code&gt;Client Secret&lt;/code&gt; and a &lt;code&gt;Redirect URI&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As an example, we are going to use a &lt;strong&gt;Google provider&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Note that &lt;strong&gt;Light-Auth&lt;/strong&gt; can use multiple providers, but for sake of simplicity, we are going to use only one here.&lt;/p&gt;

&lt;p&gt;Once you have configure your &lt;strong&gt;Google OAUTH2&lt;/strong&gt; from the &lt;a href="https://console.cloud.google.com/apis/credentials" rel="noopener noreferrer"&gt;google admin console&lt;/a&gt;, add a &lt;code&gt;.env&lt;/code&gt; file at the root of your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;GOOGLE_CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;your_client_id_from_google_cloud&amp;gt;&lt;/span&gt;
&lt;span class="py"&gt;GOOGLE_CLIENT_SECRET&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;your_client_secret_from_google_cloud&amp;gt;&lt;/span&gt;
&lt;span class="py"&gt;GOOGLE_REDIRECT_URI&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;http://localhost/api/auth/callback/google&lt;/span&gt;

&lt;span class="py"&gt;LIGHT_AUTH_SECRET_VALUE&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;any_random_secret_used_to_secure_server_cookies&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;LIGHT_AUTH_SECRET_VALUE&lt;/code&gt; value is used to encrypt cookies, and is mandatory.&lt;/p&gt;

&lt;h3&gt;
  
  
  3) Configure vite
&lt;/h3&gt;

&lt;p&gt;Add &lt;code&gt;@light-auth/tanstack-react-start&lt;/code&gt; to the vite config as &lt;code&gt;noExternal&lt;/code&gt; to avoid the SSR context loss.&lt;/p&gt;

&lt;p&gt;If you want more info on why this step is mandatory, you can read more info here: &lt;a href="https://github.com/TanStack/router/issues/4409" rel="noopener noreferrer"&gt;SSR context loss&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// file: "./vite.config.ts"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&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="na"&gt;ssr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;noExternal&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="s1"&gt;@light-auth/tanstack-react-start&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4) Configure Light-Auth
&lt;/h3&gt;

&lt;p&gt;This file contains the authentication logic and configuration. &lt;br&gt;
The exports consts are &lt;code&gt;providers&lt;/code&gt;, &lt;code&gt;handlers&lt;/code&gt;, &lt;code&gt;signIn&lt;/code&gt;, &lt;code&gt;signOut&lt;/code&gt;, &lt;code&gt;getAuthSession&lt;/code&gt;, and &lt;code&gt;getUser&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;These constants are used throughout the application to manage authentication.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// file: "./lib/auth.ts"&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;Google&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;arctic&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;CreateLightAuth&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;@light-auth/nextjs&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;googleProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;providerName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;google&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;arctic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Google&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GOOGLE_CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GOOGLE_CLIENT_SECRET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GOOGLE_REDIRECT_URI&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handlers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signOut&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getAuthSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getUser&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CreateLightAuth&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;googleProvider&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;h3&gt;
  
  
  5) Add Light-Auth Handlers
&lt;/h3&gt;

&lt;p&gt;This file contains the authentication handlers for the API.&lt;br&gt;
These handlers are responsible for processing authentication requests and returning the appropriate responses.&lt;br&gt;
The handlers are exported as &lt;code&gt;GET&lt;/code&gt; and &lt;code&gt;POST&lt;/code&gt; methods.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// file: "./routes/api/auth/$.tsx"&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;createServerFileRoute&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;@tanstack/react-start/server&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;handlers&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;@/lib/auth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ServerRoute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createServerFileRoute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/auth/$&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handlers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Everything is now configured. &lt;br&gt;
You just need now to implement your login page and use the exports constants everywhere you need them.&lt;/p&gt;
&lt;h3&gt;
  
  
  6) Add login page
&lt;/h3&gt;

&lt;p&gt;This file contains the login page using a form action to login using your provider.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You can also use client components to trigger the login process.&lt;br&gt;
See the documentation &lt;a href="https://lightauth.github.io/docs/client-server-auth" rel="noopener noreferrer"&gt;Client Components&lt;/a&gt; for more information.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// file: "./routes/login.tsx"&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;createFileRoute&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;@tanstack/react-router&lt;/span&gt;&lt;span class="dl"&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;createServerFn&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;@tanstack/react-start&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;signIn&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;@/lib/auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createFileRoute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)({&lt;/span&gt;
  &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RouteComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actionSignIn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createServerFn&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;google&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;/profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;


&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RouteComponent&lt;/span&gt;&lt;span class="p"&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;actionSignIn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt; &lt;span class="nx"&gt;using&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&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;h3&gt;
  
  
  7) Use Light-Auth in your Profile page
&lt;/h3&gt;

&lt;p&gt;Retrieves the session information to check if user is authenticated or not and displays it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// file: "./routes/profile.tsx"&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;createFileRoute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Link&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;@tanstack/react-router&lt;/span&gt;&lt;span class="dl"&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;createServerFn&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;@tanstack/react-start&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;getAuthSession&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;laGetAuthSession&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;@/lib/auth&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;getAuthSession&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createServerFn&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&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="nf"&gt;handler&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="nf"&gt;laGetAuthSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createFileRoute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)({&lt;/span&gt;
  &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RouteComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getAuthSession&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="nx"&gt;session&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RouteComponent&lt;/span&gt;&lt;span class="p"&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;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useLoaderData&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;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&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="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&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="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;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;✅ You are logged in!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&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;Session Email: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&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;Session Provider: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;providerName&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;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="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;⚠️ You are not logged in&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&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;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/login"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; Go to Login Page &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&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="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;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ✅ Conclusion
&lt;/h2&gt;

&lt;p&gt;By following these steps, you’ve successfully integrated Light-Auth into your TanStack React Start application. &lt;/p&gt;

&lt;p&gt;This setup provides a secure, scalable, and easy-to-maintain authentication system with minimal configuration.&lt;/p&gt;

&lt;p&gt;Next steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add more OAuth providers (GitHub, Twitter, etc.)&lt;/li&gt;
&lt;li&gt;Implement role-based access control&lt;/li&gt;
&lt;li&gt;Secure API routes with session validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more details, visit the &lt;a href="https://lightauth.github.io" rel="noopener noreferrer"&gt;Light-Auth&lt;/a&gt; official website.&lt;/p&gt;

</description>
      <category>authentication</category>
      <category>react</category>
      <category>tanstack</category>
      <category>security</category>
    </item>
    <item>
      <title>Light-Auth: A lightweight auth. sdk for SSR frameworks</title>
      <dc:creator>Sébastien Pertus</dc:creator>
      <pubDate>Thu, 07 Aug 2025 11:14:00 +0000</pubDate>
      <link>https://dev.to/mimetis/light-auth-a-lightweight-auth-sdk-for-ssr-frameworks-9o8</link>
      <guid>https://dev.to/mimetis/light-auth-a-lightweight-auth-sdk-for-ssr-frameworks-9o8</guid>
      <description>&lt;p&gt;&lt;a href="https://lightauth.github.io" rel="noopener noreferrer"&gt;Light-Auth&lt;/a&gt; is a lightweight authentication solution designed for simplicity and ease of integration.&lt;/p&gt;

&lt;p&gt;It provides essential authentication features with minimal configuration, making it ideal for small projects, prototypes, or applications that require straightforward user sign-in functionality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Simple setup and configuration&lt;/li&gt;
&lt;li&gt;Supports basic authentication flows&lt;/li&gt;
&lt;li&gt;Minimal dependencies&lt;/li&gt;
&lt;li&gt;Easily extensible for custom requirements&lt;/li&gt;
&lt;li&gt;Server side an Client side components&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Framework Compatibility
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Light-Auth&lt;/strong&gt; shines across your favorite frameworks! Whether you’re building with:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Framework&lt;/th&gt;
&lt;th&gt;NPM Package&lt;/th&gt;
&lt;th&gt;GitHub Sample&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="https://media2.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%2Fvil6quled8d5diil48a9.jpg" alt="NextJS" width="50" height="51"&gt; &lt;strong&gt;Next.js&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.npmjs.com/package/@light-auth/nextjs" rel="noopener noreferrer"&gt;light-auth-nextjs&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/lightauth/light-auth-nextjs-sample-one" rel="noopener noreferrer"&gt;Next.js Sample&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="https://media2.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%2Fcu11lgbe9idqha6nu2xc.jpg" alt="Astro" width="50" height="56"&gt; &lt;strong&gt;Astro&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.npmjs.com/package/@light-auth/astro" rel="noopener noreferrer"&gt;light-auth-astro&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/lightauth/light-auth-astro-sample-one" rel="noopener noreferrer"&gt;Astro Sample&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="https://media2.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%2Fq2qrfszl4jcme7ia2ua4.jpg" alt="Nuxt" width="50" height="38"&gt; &lt;strong&gt;Nuxt&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.npmjs.com/package/@light-auth/nuxt" rel="noopener noreferrer"&gt;light-auth-nuxt&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/lightauth/light-auth-nuxt-sample-one" rel="noopener noreferrer"&gt;Nuxt Sample&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="https://media2.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%2F3ugl8fja38u8l6irh71k.jpg" alt="SvelteKit" width="50" height="54"&gt; &lt;strong&gt;SvelteKit&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.npmjs.com/package/@light-auth/sveltekit" rel="noopener noreferrer"&gt;light-auth-sveltekit&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/lightauth/light-auth-sveltekit-sample-one" rel="noopener noreferrer"&gt;SvelteKit Sample&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="https://media2.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%2Fwg3ziidace1d4f1mzzev.jpg" alt="Express" width="50" height="28"&gt; &lt;strong&gt;Express&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.npmjs.com/package/@light-auth/express" rel="noopener noreferrer"&gt;light-auth-express&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/lightauth/light-auth-express-sample-one" rel="noopener noreferrer"&gt;Express Sample&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="https://media2.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%2F6j26xat6cq0kjetkx5rx.jpg" alt="Tanstack Start" width="50" height="50"&gt; &lt;strong&gt;Tanstack Start&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.npmjs.com/package/@light-auth/tanstack-react-start" rel="noopener noreferrer"&gt;light-auth-tanstack-react-start&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/lightauth/light-auth-tanstack-sample-one" rel="noopener noreferrer"&gt;Tanstack Start Sample&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Light Auth&lt;/strong&gt; integrates seamlessly, letting you add authentication with a sparkle ✨ to any stack!&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;This getting started is based on the  &lt;a href="https://www.npmjs.com/package/@light-auth/nextjs" rel="noopener noreferrer"&gt;light-auth-nextjs&lt;/a&gt; package.&lt;/p&gt;

&lt;p&gt;You will find examples for all others frameworks in each relevant repository&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://lightauth.github.io" rel="noopener noreferrer"&gt;Light Auth&lt;/a&gt; documentation has also a lot of code examples for various scenario.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  1) Installing Light Auth
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nt"&gt;-i&lt;/span&gt; @light-auth/nextjs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2) Configuring Light Auth
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Light-Auth&lt;/strong&gt; is using &lt;strong&gt;Arctic providers&lt;/strong&gt;: Arctic is a collection of OAuth 2.0 clients for popular providers.&lt;/p&gt;

&lt;p&gt;You will find the complete list of Arctic providers on the official website: &lt;a href="https://arcticjs.dev/" rel="noopener noreferrer"&gt;Arctic v3&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each provider needs to be configure, usually with a &lt;code&gt;ClientId&lt;/code&gt;, a &lt;code&gt;Client Secret&lt;/code&gt; and a &lt;code&gt;Redirect URI&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As an example, we are going to use a &lt;strong&gt;Google provider&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Note that &lt;strong&gt;Light-Auth&lt;/strong&gt; can use multiple providers, but for sake of simplicity, we are going to use only one here.&lt;/p&gt;

&lt;p&gt;Once you have configure your &lt;strong&gt;Google OAUTH2&lt;/strong&gt; from the &lt;a href="https://console.cloud.google.com/apis/credentials" rel="noopener noreferrer"&gt;google admin console&lt;/a&gt;, add a &lt;code&gt;.env&lt;/code&gt; file at the root of your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;GOOGLE_CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;your_client_id_from_google_cloud&amp;gt;&lt;/span&gt;
&lt;span class="py"&gt;GOOGLE_CLIENT_SECRET&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;your_client_secret_from_google_cloud&amp;gt;&lt;/span&gt;
&lt;span class="py"&gt;GOOGLE_REDIRECT_URI&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;http://localhost/api/auth/callback/google&lt;/span&gt;

&lt;span class="py"&gt;LIGHT_AUTH_SECRET_VALUE&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;any_random_secret_used_to_secure_server_cookies&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;LIGHT_AUTH_SECRET_VALUE&lt;/code&gt; value is used to encrypt cookies, and is mandatory.&lt;/p&gt;

&lt;p&gt;Now, you can add a new file to configure &lt;strong&gt;Light-auth&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The results from the &lt;code&gt;CreateLightAuth&lt;/code&gt; call will be used everywhere else to allow you to login, logout, get session and user metadata.&lt;/p&gt;

&lt;p&gt;You can place this file wherever you want.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// file: "./lib/auth.ts"&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;Google&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;arctic&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;CreateLightAuth&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;@light-auth/nextjs&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;googleProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;providerName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;google&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;arctic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Google&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GOOGLE_CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GOOGLE_CLIENT_SECRET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GOOGLE_REDIRECT_URI&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handlers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signOut&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getAuthSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getUser&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 
     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CreateLightAuth&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;googleProvider&lt;/span&gt;&lt;span class="p"&gt;]})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3) Adding Light Auth Handlers
&lt;/h3&gt;

&lt;p&gt;Handlers are here to intercept all authentication requests used to authenticate your users:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// file: "./app/api/auth/[...lightauth].ts"&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;handlers&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;@/lib/auth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;POST&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;handlers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4) Adding login page
&lt;/h3&gt;

&lt;p&gt;You have multiple way to launch the authentication process. For this example, we are going to use a &lt;a href="https://nextjs.org/docs/app/getting-started/updating-data" rel="noopener noreferrer"&gt;Server Function&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also used a full client side technic, if you want to.&lt;br&gt;&lt;br&gt;
Check the official documentation for more on &lt;a href="https://lightauth.github.io/docs/client-server-auth" rel="noopener noreferrer"&gt;client side interaction&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// file: "./app/login.tsx"&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;signIn&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;@/lib/auth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;LoginPage&lt;/span&gt;&lt;span class="p"&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="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;
        &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;async &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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;google&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;/profile&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="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;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;login&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&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;form&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;h3&gt;
  
  
  5) Using Light Auth
&lt;/h3&gt;

&lt;p&gt;Once your user is authenticated, you can use the &lt;strong&gt;Light-Auth&lt;/strong&gt; SDK to access various information about the logged (or not) user.&lt;/p&gt;

&lt;p&gt;In this small example, we are using the session to check if user is authenticated and can access privates ressources:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// file: "./app/profile.tsx"&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;getAuthSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signIn&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;@/lib/auth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&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;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getAuthSession&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="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&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="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;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;✅ You are logged in!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&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;Session Email: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&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;Session Provider: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;providerName&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;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="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; You are not logged &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&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="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;);&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 need more info, do not hesitate to ping me &lt;a href="https://x.com/sebpertus" rel="noopener noreferrer"&gt;@sebpertus&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also check the complete documentation here: &lt;a href="https://lightauth.github.io/" rel="noopener noreferrer"&gt;https://lightauth.github.io&lt;/a&gt;&lt;/p&gt;

</description>
      <category>oauth2</category>
      <category>nextjs</category>
      <category>nuxt</category>
      <category>tanstack</category>
    </item>
    <item>
      <title>Using DNS01 challenge and Let's Encrypt to secure your AKS kubernetes cluster</title>
      <dc:creator>Sébastien Pertus</dc:creator>
      <pubDate>Fri, 12 Jun 2020 12:02:04 +0000</pubDate>
      <link>https://dev.to/mimetis/using-dns01-challenge-and-let-s-encrypt-to-secure-your-aks-kubernetes-cluster-5g42</link>
      <guid>https://dev.to/mimetis/using-dns01-challenge-and-let-s-encrypt-to-secure-your-aks-kubernetes-cluster-5g42</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR;
&lt;/h2&gt;

&lt;p&gt;This blog post is all about "how to get a certificate using the DNS01 challenge" to secure your Kubernetes cluster running inside AKS.&lt;/p&gt;

&lt;p&gt;You will find the repository code source on github : &lt;a href="https://github.com/Mimetis/AKS_DNS01Solver"&gt;https://github.com/Mimetis/AKS_DNS01Solver&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To be able to continue, you need to :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Own a domain name.&lt;/li&gt;
&lt;li&gt;Be able to create an NS record from within your domain provider to be able to redirect all that sub domain queries to Azure DNS Zone.&lt;/li&gt;
&lt;li&gt;Have an Azure subscription to create your own AKS cluster.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jsTLHEQI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/y5v462zpaqtbt11op4l8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jsTLHEQI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/y5v462zpaqtbt11op4l8.png" alt="Schema"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Intoduction
&lt;/h2&gt;

&lt;p&gt;The most common way to secure an &lt;a href="https://azure.microsoft.com/en-us/services/kubernetes-service/"&gt;AKS&lt;/a&gt; entry endpoint cluster (basically your ingress) is to allow only &lt;em&gt;https&lt;/em&gt; queries through your ingress (like nginx or traefik)&lt;/p&gt;

&lt;p&gt;A usefull pattern is to use the combo &lt;a href="https://letsencrypt.org/"&gt;Let's Encrypt&lt;/a&gt; and &lt;a href="https://cert-manager.io/docs/"&gt;Cert manager&lt;/a&gt; to get a valid certificate from &lt;strong&gt;Let's encrypt&lt;/strong&gt;, that will be renewed over time, automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's Encrypt&lt;/strong&gt; uses the &lt;strong&gt;ACME&lt;/strong&gt; protocol to verify that you control a given domain name and then to issue a valid certificate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solving challenges
&lt;/h2&gt;

&lt;p&gt;In order for the &lt;strong&gt;ACME CA&lt;/strong&gt; server to verify that a client owns the domain, a certificate is being requested for, the client must complete &lt;strong&gt;challenges&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We have mainly two types of challenges available:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTTP01&lt;/strong&gt; challenge is completed by presented a computed key on a regular &lt;strong&gt;HTTP&lt;/strong&gt; url endpoint.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DNS01&lt;/strong&gt; challenge is completed by presented a computed key that is present in a &lt;strong&gt;DNS TXT&lt;/strong&gt; record.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  HTTP01 problem
&lt;/h2&gt;

&lt;p&gt;In some circumstances, you just want your cluster to be available using &lt;strong&gt;only&lt;/strong&gt; a secure connection over &lt;strong&gt;https&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
The main issue with the &lt;strong&gt;HTTP01&lt;/strong&gt; solving challenge is that you have to let an url endpoint opened on port 80.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IF&lt;/strong&gt; you are considering this as a security issue, you may want to resolve your challenge, using the &lt;strong&gt;DNS01&lt;/strong&gt; challenge.&lt;/p&gt;
&lt;h2&gt;
  
  
  Using DNS01 challenge
&lt;/h2&gt;

&lt;p&gt;We're going to explain how to implement a &lt;strong&gt;DNS01&lt;/strong&gt; challenge in an &lt;strong&gt;Azure&lt;/strong&gt; environnement, using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AKS&lt;/strong&gt; as a kubernetes cluster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NGINX&lt;/strong&gt; as ingress.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cert Manager&lt;/strong&gt; as a certificate management controller.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Azure DNS Zone&lt;/strong&gt; as a dns resolution engine.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Obviously we will use some useful (and almost mandatory is you are working with kubernetes) tools like &lt;strong&gt;kubectl&lt;/strong&gt; and &lt;strong&gt;helm&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The sample application used is the &lt;a href="https://github.com/Azure-Samples/azure-voting-app-redis"&gt;Azure voting application sample&lt;/a&gt; that will be slightly modified to add an &lt;strong&gt;nginx&lt;/strong&gt; controller as an ingress.&lt;/p&gt;
&lt;h2&gt;
  
  
  DNS zone
&lt;/h2&gt;

&lt;p&gt;In this example, I'm working with my own domain called &lt;strong&gt;dotmim.com&lt;/strong&gt; (I used to have a blog on this domain.. long time ago !)&lt;/p&gt;

&lt;p&gt;I will create a sub domain that will redirect all the trafic for this sub domain to my DNS Zone.&lt;/p&gt;

&lt;p&gt;First of all, you may want to create your &lt;strong&gt;Azure DNS zone&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
Keep in mind that your dns zone should be a sub domain of your domain.&lt;/p&gt;

&lt;p&gt;In the screenshot below, we will manage a subdomain called &lt;strong&gt;vote.dotmim.com&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3kIbg9o3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/16gm5zb797diix5q2zh4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3kIbg9o3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/16gm5zb797diix5q2zh4.png" alt="DNS Zone creation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once created, just copy the &lt;strong&gt;Name server 1&lt;/strong&gt; property (in my case &lt;em&gt;ns1-02.azure-dns.com.&lt;/em&gt;)&lt;/p&gt;

&lt;p&gt;From my domain provider, i'm registering a new &lt;strong&gt;NS&lt;/strong&gt; entry that will redirect everything to my &lt;strong&gt;DNS Zone&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---cpLKJn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/njl97apdcuwg7otsmyxo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---cpLKJn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/njl97apdcuwg7otsmyxo.png" alt="NS Redirection"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can check that the redirection is working by doing a quick &lt;code&gt;ns lookup&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;nslookup &lt;span class="nt"&gt;-type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;SOA dotmim.com
Non-authoritative answer:
dotmim.com
        origin &lt;span class="o"&gt;=&lt;/span&gt; ns1.amen.fr


nslookup &lt;span class="nt"&gt;-type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;SOA vote.dotmim.com
Non-authoritative answer:
vote.dotmim.com
        origin &lt;span class="o"&gt;=&lt;/span&gt; ns1-02.azure-dns.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(Some informations have been removed for clarity)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As you can see the root domain is handled by my domain provider and the &lt;em&gt;vote.*&lt;/em&gt; sub domain is now handled by my new created Azure DNS Zone.&lt;/p&gt;

&lt;h3&gt;
  
  
  nginx ingress controller
&lt;/h3&gt;

&lt;p&gt;The application we want to deploy is quite simple and based on the &lt;a href="https://github.com/Azure-Samples/azure-voting-app-redis"&gt;Azure voting application sample&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You will find the deployment script here : &lt;a href="//vote.yaml"&gt;https://github.com/Mimetis/AKS_DNS01Solver/vote.yaml&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The only modification is that we will use an nginx ingress as entry point instead of exposing the vote application directly.&lt;/p&gt;

&lt;p&gt;Adding nginx is quite straightforward using the official helm chart:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a namespace for your ingress resources&lt;/span&gt;
kubectl create namespace ingress-basic

&lt;span class="c"&gt;# Use Helm to deploy an NGINX ingress controller&lt;/span&gt;
helm &lt;span class="nb"&gt;install &lt;/span&gt;nginx stable/nginx-ingress &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--namespace&lt;/span&gt; ingress-basic &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--set&lt;/span&gt; controller.replicaCount&lt;span class="o"&gt;=&lt;/span&gt;2 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--set&lt;/span&gt; controller.nodeSelector.&lt;span class="s2"&gt;"beta&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;kubernetes&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;io/os"&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;linux &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--set&lt;/span&gt; defaultBackend.nodeSelector.&lt;span class="s2"&gt;"beta&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;kubernetes&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;io/os"&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;linux
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  cert-manager
&lt;/h3&gt;

&lt;p&gt;to be able to manage everything, we are installing as well &lt;strong&gt;cert-manager&lt;/strong&gt; on the cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Deploy custom resources definition&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;--validate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; https://github.com/jetstack/cert-manager/releases/download/v0.14.1/cert-manager.crds.yaml

&lt;span class="c"&gt;# create namespace for cert&lt;/span&gt;
kubectl create namespace cert-manager  

&lt;span class="c"&gt;# Add repo&lt;/span&gt;
helm repo add jetstack https://charts.jetstack.io
helm repo update

&lt;span class="c"&gt;# Label the ingress-basic namespace to disable resource validation&lt;/span&gt;
kubectl label namespace ingress-basic cert-manager.io/disable-validation&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;

&lt;span class="c"&gt;# Install cert manager&lt;/span&gt;
helm &lt;span class="nb"&gt;install &lt;/span&gt;cert-manager jetstack/cert-manager &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;--namespace&lt;/span&gt; cert-manager &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;--version&lt;/span&gt; v0.14.1 &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;--set&lt;/span&gt; ingressShim.defaultIssuerName&lt;span class="o"&gt;=&lt;/span&gt;letsencrypt-staging &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;--set&lt;/span&gt; ingressShim.defaultIssuerKind&lt;span class="o"&gt;=&lt;/span&gt;ClusterIssuer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Service principal
&lt;/h3&gt;

&lt;p&gt;Once it's done, we need a &lt;strong&gt;service principal&lt;/strong&gt; to be able to reach the DNS Zone from within our cluster. &lt;/p&gt;

&lt;p&gt;For the sake of simplicity, I will create a simple service principal without any role assignement, but you may want to look at the &lt;strong&gt;cert-manager&lt;/strong&gt; official documentation to ensure you have the least privileges assigned to your spn : &lt;a href="https://cert-manager.io/docs/configuration/acme/dns01/azuredns/"&gt;Azure DNS configuration&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once created, we will save it as a &lt;strong&gt;secret&lt;/strong&gt; in the AKS cluster.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a service principal for DNS validation&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;az ad sp create-for-rbac &lt;span class="nt"&gt;--name&lt;/span&gt; spcertmanageridentity

Creating a role assignment under the scope of &lt;span class="s2"&gt;"/subscriptions/subid000-eeee-ffff-gggg-hhhhhhhhhhhh"&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"appId"&lt;/span&gt;: &lt;span class="s2"&gt;"appid000-aaaa-bbbb-cccc-dddddddddddd"&lt;/span&gt;,
  &lt;span class="s2"&gt;"displayName"&lt;/span&gt;: &lt;span class="s2"&gt;"spcertmanageridentity"&lt;/span&gt;,
  &lt;span class="s2"&gt;"name"&lt;/span&gt;: &lt;span class="s2"&gt;"http://spcertmanageridentity"&lt;/span&gt;,
  &lt;span class="s2"&gt;"password"&lt;/span&gt;: &lt;span class="s2"&gt;"password-aaaa-bbbb-cccc-dddddddddddd"&lt;/span&gt;,
  &lt;span class="s2"&gt;"tenant"&lt;/span&gt;: &lt;span class="s2"&gt;"tenant00-aaaa-bbbb-cccc-dddddddddddd"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

kubectl create secret generic azuredns-config &lt;span class="nt"&gt;--from-literal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;client-secret&lt;span class="o"&gt;=&lt;/span&gt;password-aaaa-bbbb-cccc-dddddddddddd &lt;span class="nt"&gt;-n&lt;/span&gt; cert-manager

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



&lt;h3&gt;
  
  
  DNS Issuer
&lt;/h3&gt;

&lt;p&gt;This is where everything is happening.&lt;br&gt;&lt;br&gt;
Your DNS issuer is the configuration that will be used by cert manager to be able to create the TXT record requested by the ACME CA (Let's Encrypt)&lt;/p&gt;

&lt;p&gt;Here is a DNS issuer used with the Let's Encrypt staging endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cert-manager.io/v1alpha2&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ClusterIssuer&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;letsencrypt-staging&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;acme&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://acme-staging-v02.api.letsencrypt.org/directory&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yourname@youremail.com&lt;/span&gt;
    &lt;span class="c1"&gt;# Name of a secret used to store the ACME account private key&lt;/span&gt;
    &lt;span class="na"&gt;privateKeySecretRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;letsencrypt&lt;/span&gt;
    &lt;span class="c1"&gt;# ACME DNS-01 provider configurations&lt;/span&gt;
    &lt;span class="na"&gt;solvers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;dns01&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;azuredns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;clientID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;appid000-aaaa-bbbb-cccc-dddddddddddd&lt;/span&gt;
          &lt;span class="na"&gt;clientSecretSecretRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;azuredns-config&lt;/span&gt;
            &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;client-secret&lt;/span&gt;
          &lt;span class="na"&gt;subscriptionID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;subid000-eeee-ffff-gggg-hhhhhhhhhhhh&lt;/span&gt;
          &lt;span class="na"&gt;tenantID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tenant00-aaaa-bbbb-cccc-dddddddddddd&lt;/span&gt;
          &lt;span class="na"&gt;resourceGroupName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rgdns&lt;/span&gt;
          &lt;span class="na"&gt;hostedZoneName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vote.dotmim.com&lt;/span&gt;
          &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AzurePublicCloud&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Do not hesitate to create all the cluster issuer you need: DNS with Let's Encrypt staging / DNS with Let's Encrypt production and so on...&lt;br&gt;&lt;br&gt;
You will use the one you need from the ingress configuration object.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; dnsissuer.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  ingress
&lt;/h3&gt;

&lt;p&gt;Now that we've deployed everything we need, just create an ingress with the correct values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;extensions/v1beta1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Ingress&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;kubernetes.io/ingress.class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
    &lt;span class="s"&gt;ingress.kubernetes.io/ssl-redirect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;false"&lt;/span&gt;
    &lt;span class="s"&gt;ingress.kubernetes.io/force-ssl-redirect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;false"&lt;/span&gt; 
    &lt;span class="c1"&gt;#nginx.ingress.kubernetes.io/rewrite-target: /&lt;/span&gt;
    &lt;span class="s"&gt;cert-manager.io/cluster-issuer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;letsencrypt-staging&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vote-ingress&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;tls&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;vote.dotmim.com&lt;/span&gt;
      &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tls-secret&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vote.dotmim.com&lt;/span&gt;
      &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;serviceName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;azure-vote-front&lt;/span&gt;
              &lt;span class="na"&gt;servicePort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Debug
&lt;/h3&gt;

&lt;p&gt;Check that your certificate has been correctly issued, using the describe command on objects &lt;code&gt;Certificate&lt;/code&gt;, &lt;code&gt;CertificateRequest&lt;/code&gt; and &lt;code&gt;Order&lt;/code&gt; :&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Once again, removing unrelevant part, for clarity)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;
kubectl describe cert tls-secret
Name:         tls-secret
Kind:         Certificate
Metadata:
  Owner References:
    Kind:                  Ingress
    Name:                  vote-ingress
Spec:
  Dns Names:
    vote.dotmim.com
  Issuer Ref:
    Group:      cert-manager.io
    Kind:       ClusterIssuer
    Name:       letsencrypt-staging
  Secret Name:  tls-secret
Events:
  Type    Reason     Age   From          Message
  &lt;span class="nt"&gt;----&lt;/span&gt;    &lt;span class="nt"&gt;------&lt;/span&gt;     &lt;span class="nt"&gt;----&lt;/span&gt;  &lt;span class="nt"&gt;----&lt;/span&gt;          &lt;span class="nt"&gt;-------&lt;/span&gt;
  Normal  Requested  8s    cert-manager  Created new CertificateRequest resource &lt;span class="s2"&gt;"tls-secret-1150149038"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The Certificate request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe  CertificateRequest tls-secret-1150149038
Name:         tls-secret-1150149038
Kind:         CertificateRequest
Metadata:
  Owner References:
    Kind:                  Certificate
    Name:                  tls-secret
Spec:
  Issuer Ref:
    Group:  cert-manager.io
    Kind:   ClusterIssuer
    Name:   letsencrypt-staging
Events:
  Type    Reason        Age   From          Message
  &lt;span class="nt"&gt;----&lt;/span&gt;    &lt;span class="nt"&gt;------&lt;/span&gt;        &lt;span class="nt"&gt;----&lt;/span&gt;  &lt;span class="nt"&gt;----&lt;/span&gt;          &lt;span class="nt"&gt;-------&lt;/span&gt;
  Normal  OrderCreated  28s   cert-manager  Created Order resource default/tls-secret-1150149038-248511818
  Normal  OrderPending  28s   cert-manager  Waiting on certificate issuance from order default/tls-secret-1150149038-248511818: &lt;span class="s2"&gt;""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And eventually the Order :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe order tls-secret-1150149038-248511818
Name:         tls-secret-1150149038-248511818
Kind:         Order
Metadata:
  Owner References:
    Kind:                  CertificateRequest
    Name:                  tls-secret-1150149038
Spec:
  Dns Names:
    vote.dotmim.com
  Issuer Ref:
    Group:  cert-manager.io
    Kind:   ClusterIssuer
    Name:   letsencrypt-staging
Status:
  Certificate:   LS0tLS1CRUdJTiBDRVJUSU....
Events:
  Type    Reason    Age   From          Message
  &lt;span class="nt"&gt;----&lt;/span&gt;    &lt;span class="nt"&gt;------&lt;/span&gt;    &lt;span class="nt"&gt;----&lt;/span&gt;  &lt;span class="nt"&gt;----&lt;/span&gt;          &lt;span class="nt"&gt;-------&lt;/span&gt;
  Normal  Created   113s  cert-manager  Created Challenge resource &lt;span class="s2"&gt;"tls-secret-1150149038-248511818-2518637675"&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;domain &lt;span class="s2"&gt;"vote.dotmim.com"&lt;/span&gt;
  Normal  Complete  49s   cert-manager  Order completed successfully
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once you've reached that point, your certificate has been issued correctly. You can check once again the certificate and confirms it's correcty configured and downloaded in your cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;(&lt;/span&gt;base&lt;span class="o"&gt;)&lt;/span&gt; spertus@MSI2019:~/cert&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl describe cert tls-secret
Name:         tls-secret
Kind:         Certificate
Metadata:
Spec:
Status:
  Conditions:
    Last Transition Time:  2020-06-12T09:57:10Z
    Message:               Certificate is up to &lt;span class="nb"&gt;date &lt;/span&gt;and has not expired
    Reason:                Ready
  Not After:               2020-09-10T08:57:10Z
Events:
  Type    Reason     Age                 From          Message
  &lt;span class="nt"&gt;----&lt;/span&gt;    &lt;span class="nt"&gt;------&lt;/span&gt;     &lt;span class="nt"&gt;----&lt;/span&gt;                &lt;span class="nt"&gt;----&lt;/span&gt;          &lt;span class="nt"&gt;-------&lt;/span&gt;
  Normal  Requested  10m                 cert-manager  Created new CertificateRequest resource &lt;span class="s2"&gt;"tls-secret-1150149038"&lt;/span&gt;
  Normal  Issued     9m25s &lt;span class="o"&gt;(&lt;/span&gt;x2 over 8d&lt;span class="o"&gt;)&lt;/span&gt;  cert-manager  Certificate issued successfully
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Last step: Redirection
&lt;/h2&gt;

&lt;p&gt;Now that you're able to reach your https entry point, don't forget to redirect all the trafic to your AKS cluster:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G8SbfrRU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3wtx4o1fu747ytg3vlb1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G8SbfrRU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3wtx4o1fu747ytg3vlb1.png" alt="Redirect to AKS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, I'm able to reach my vote application, using an &lt;strong&gt;HTTPS&lt;/strong&gt; connection and a staging &lt;strong&gt;Let's Encrypt&lt;/strong&gt; certificate !&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Q78bC_la--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/yrfm3jrrlfmkjrc93rtz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Q78bC_la--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/yrfm3jrrlfmkjrc93rtz.png" alt="Web site using FAKE LE certificate"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>azure</category>
      <category>certmanager</category>
      <category>letsencrypt</category>
    </item>
    <item>
      <title>Part 2: How to Synchronize relational databases with Dotmim.Sync</title>
      <dc:creator>Sébastien Pertus</dc:creator>
      <pubDate>Wed, 19 Feb 2020 18:42:27 +0000</pubDate>
      <link>https://dev.to/mimetis/how-to-synchronize-relational-databases-with-dotmim-sync-part-2-1gba</link>
      <guid>https://dev.to/mimetis/how-to-synchronize-relational-databases-with-dotmim-sync-part-2-1gba</guid>
      <description>&lt;p&gt;This post is part of a series about &lt;a href="https://github.com/Mimetis/Dotmim.Sync"&gt;Dotmim.Sync&lt;/a&gt; on how to synchronize relations databases between a server hub and multiple client members:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://dev.to/mimetis/how-to-synchronize-relational-databases-with-dotmim-sync-5693"&gt;Part 1&lt;/a&gt;: Introduction to Dotmim.Sync: Hello Sync !&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/mimetis/how-to-synchronize-relational-databases-with-dotmim-sync-part-2-1gba"&gt;Part 2&lt;/a&gt;: Protecting your hub behind a web API, through ASP.Net Core Web Api&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In &lt;a href="https://dev.to/mimetis/how-to-synchronize-relational-databases-with-dotmim-sync-5693"&gt;Part 1&lt;/a&gt;, we saw the most straightforward way to synchronize a server hub database with any kind of client database.&lt;br&gt;
This first sample was based on a simple &lt;code&gt;tcp&lt;/code&gt; connection between the server and the client.&lt;br&gt;
Obviously, in a real world scenario, you don't expose your hub database directly.&lt;/p&gt;

&lt;p&gt;Rather than exposing your database &lt;em&gt;to the world&lt;/em&gt;, it could be better to protect it via a web proxy, usually a Web API.&lt;/p&gt;

&lt;p&gt;To sum up, in &lt;a href="https://dev.to/mimetis/how-to-synchronize-relational-databases-with-dotmim-sync-5693"&gt;Part 1&lt;/a&gt;, we saw how to use the &lt;code&gt;SqlSyncProvider&lt;/code&gt; and &lt;code&gt;SqliteSyncProvider&lt;/code&gt; providers to communicate with our databases (client and server), then we saw how to use a &lt;code&gt;SyncAgent&lt;/code&gt; instance to launch a direct synchronization over &lt;code&gt;tcp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Today we are going to see how we can use the &lt;code&gt;WebRemoteOrchestrator&lt;/code&gt; proxy from the client side and the &lt;code&gt;WebServerAgent&lt;/code&gt; from the server side, to allow a smooth sync process from any client and our server, through a web api, managed by a simple &lt;strong&gt;ASP.Net Core Web Api&lt;/strong&gt; project.&lt;/p&gt;

&lt;p&gt;As a reminder, here is the &lt;strong&gt;console&lt;/strong&gt; application we've created. &lt;br&gt;
It's our base project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;SynchronizeAdventureWorksAsync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;serverProvider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SqlSyncProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;GetDatabaseConnectionString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AdventureWorks"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;clientProvider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SqliteSyncProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"advworks.db"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;setup&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SyncSetup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ProductCategory"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ProductModel"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Product"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Address"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Customer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"CustomerAddress"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"SalesOrderHeader"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"SalesOrderDetail"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SyncAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clientProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serverProvider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;progress&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;SynchronousProgress&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ProgressArgs&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; 
            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SyncStage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;:\t&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sync Start"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;syncContext&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SynchronizeAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;syncContext&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&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="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadKey&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;ConsoleKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Escape&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;Now, we're going to separate the &lt;em&gt;server side&lt;/em&gt; and the &lt;em&gt;client side&lt;/em&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Server Side
&lt;/h1&gt;

&lt;p&gt;First of all, we need to create a &lt;strong&gt;Web API&lt;/strong&gt; project to support our server hub proxy.&lt;br&gt;
You have multiples choices to create a Web API project within &lt;strong&gt;.Net Core&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using the CLI&lt;/li&gt;
&lt;li&gt;Using Visual Studio&lt;/li&gt;
&lt;li&gt;Using Visual Studio Code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You have a complete tutorial available here : &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-web-api"&gt;https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-web-api&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Create the Web Api project
&lt;/h2&gt;

&lt;p&gt;For this sample, we can use eiter the command lines or the Visual Studio wizard:&lt;/p&gt;

&lt;p&gt;Command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet new webapi &lt;span class="nt"&gt;-o&lt;/span&gt; DotmimSyncWebServer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visual Studio Wizard:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aQcyNawj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/u3fg9sdz1p5s4fcoeql2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aQcyNawj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/u3fg9sdz1p5s4fcoeql2.png" alt="Visual Studio Wizard" width="600" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once restored, here is our final folder architecture:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--96Lj1Z5n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/p7gdbvhv5zjz49x4jicf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--96Lj1Z5n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/p7gdbvhv5zjz49x4jicf.png" alt="Web projects" width="358" height="264"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Install the Dotmim.Sync packages
&lt;/h2&gt;

&lt;p&gt;Now, we need to add all the &lt;code&gt;Dotmim.Sync&lt;/code&gt; components we need on the server side:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;SqlSyncProvider&lt;/code&gt; for handling the communication between our &lt;strong&gt;Sql Server&lt;/strong&gt; hub instance and the exposed web API.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;WebRemoteOrchestrator&lt;/code&gt; proxy that will encapsulate all the call to the sync provider, using a &lt;code&gt;Serializer&lt;/code&gt; (&lt;code&gt;Json&lt;/code&gt; as default) to send and receive messages through &lt;code&gt;http&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using nuget, here are our final web project dependencies:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SsP9n49E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/h7n9114hiv3m0tmtgis0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SsP9n49E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/h7n9114hiv3m0tmtgis0.png" alt="Web server packages" width="800" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Obviously, you can add these nuget packages, through the console, if you're using &lt;strong&gt;Visual Studio Code&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package Dotmim.Sync.SqlServer
dotnet add package Dotmim.Sync.Web.Server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create a new empty sync controller
&lt;/h2&gt;

&lt;p&gt;Then, we can create an empty controller called &lt;code&gt;SyncController&lt;/code&gt; inside the &lt;code&gt;./Controllers&lt;/code&gt; folder (you can delete the generated WeatherForecast controller if you want)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;DotmimSyncWebServer.Controllers&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"api/[controller]"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SyncController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&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;h2&gt;
  
  
  Add the connection string to config file
&lt;/h2&gt;

&lt;p&gt;Of course, we need to connect to the database, and we don't want to hard code the connection string. &lt;br&gt;
We can add this value to the &lt;code&gt;appsettings.json&lt;/code&gt; file, already available in your root folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Logging"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"LogLevel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Warning"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ConnectionStrings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"DefaultConnection"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Data Source=(localdb)&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;mssqllocaldb; Initial Catalog=AdventureWorks; Integrated Security=true;"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"AllowedHosts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using Dependency injection to add the Sql Provider
&lt;/h2&gt;

&lt;p&gt;We are using a default &lt;strong&gt;ASP.Net Core&lt;/strong&gt; web template. So far, dependency injection is something really important and used a lot.&lt;br&gt;
We will use the same approach to create our sync process.&lt;/p&gt;

&lt;p&gt;The Server side is responsible of designing your sync schema. &lt;br&gt;
Once defined, this schema will be propagated to any client requesting it.&lt;/p&gt;

&lt;p&gt;Here is our&lt;code&gt;ConfigureServices()&lt;/code&gt; method in the &lt;code&gt;./startup.cs&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ConfigureServices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IServiceCollection&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddControllers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// [Required] Mandatory to be able to handle multiple sessions&lt;/span&gt;
    &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddDistributedMemoryCache&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IdleTimeout&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromMinutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="c1"&gt;// [Required] Get a connection string for your server data source&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connectionString&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ConnectionStrings"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="s"&gt;"DefaultConnection"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;// [Optional] Set the web server Options&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;WebServerOptions&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;BatchDirectory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SyncOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetDefaultUserBatchDiretory&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"server"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;


    &lt;span class="c1"&gt;// [Required] Create the setup used for your sync process&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tables&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"ProductCategory"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ProductModel"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Product"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"Address"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Customer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"CustomerAddress"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"SalesOrderHeader"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"SalesOrderDetail"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="c1"&gt;// [Optional] Defines the schema prefix and suffix for all generated objects&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;setup&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SyncSetup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tables&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// optional :&lt;/span&gt;
        &lt;span class="n"&gt;StoredProceduresPrefix&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;StoredProceduresSuffix&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;TrackingTablesPrefix&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;TrackingTablesSuffix&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="c1"&gt;// [Required] add a SqlSyncProvider acting as the server hub&lt;/span&gt;
    &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSyncServer&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SqlSyncProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&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;Notice that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We need a session system to handle multiple clients. That's why we're adding &lt;code&gt;services.AddSession()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Only &lt;em&gt;tables&lt;/em&gt; and &lt;em&gt;connection string&lt;/em&gt; are mandatory. Everything else is optional.&lt;/li&gt;
&lt;li&gt;We're using the &lt;code&gt;AddSyncServer()&lt;/code&gt; method to inject our provider in the Dependency Injection container.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Adding handler to our Sync controller
&lt;/h2&gt;

&lt;p&gt;The sync controller is really easy to implement, since everything is already handle under the cover.&lt;/p&gt;

&lt;p&gt;We just need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;Post&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;Get our &lt;code&gt;WebServerAgent&lt;/code&gt; instance from the dependency injection container, and then call the &lt;code&gt;HandleRequestAsync()&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;[Optional]&lt;/em&gt;: Create a &lt;code&gt;Get&lt;/code&gt; method to show a default page when you call the &lt;code&gt;/sync&lt;/code&gt; web page through your browser.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So far, here is the final &lt;code&gt;SyncController&lt;/code&gt; code source:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"api/[controller]"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SyncController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;WebServerAgent&lt;/span&gt; &lt;span class="n"&gt;webServerAgent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Injected thanks to Dependency Injection&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;SyncController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WebServerAgent&lt;/span&gt; &lt;span class="n"&gt;webServerAgent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;webServerAgent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;webServerAgent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// [Optional] This Get request is just here to show a default page&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteHelloAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;webServerAgent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// [Required] This Post request is called by the all Dotmim.Sync.Web.Client apis&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HttpPost&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;webServerAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HandleRequestAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpContext&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;That's all you need !&lt;/p&gt;

&lt;p&gt;If you launch the &lt;code&gt;DotmimSyncWebServer&lt;/code&gt; project and point to the &lt;code&gt;/api/sync&lt;/code&gt; web page, you should have this kind of page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nN00JWIR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xh8xb7rnxq1cmtlyd21c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nN00JWIR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xh8xb7rnxq1cmtlyd21c.png" alt="Alt Text" width="700" height="682"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: As you can see, a lot of confidential information are shown here. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This information disappears when you go into production and your environment variable is set to production: &lt;code&gt;"ASPNETCORE_ENVIRONMENT": "Production"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;You can disable it by removing the &lt;code&gt;public async Task Get()&lt;/code&gt; method from your sync controller&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Client Side
&lt;/h1&gt;

&lt;p&gt;The client side is pretty the same as our starter project.&lt;br&gt;
We just need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a the &lt;code&gt;Dotmim.Sync.Web.Client&lt;/code&gt; package to be able to use the &lt;code&gt;WebRemoteOrchestrator&lt;/code&gt; remote proxy.&lt;/li&gt;
&lt;li&gt;Change our server provider from &lt;code&gt;SqlServerProvider&lt;/code&gt; to &lt;code&gt;WebRemoteOrchestrator&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;[Optional]&lt;/em&gt; : Remove our dependency to &lt;code&gt;Dotmim.Sync.SqlServer&lt;/code&gt; since we are not using it anymore.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the final result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;serverOrchestrator&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;WebRemoteOrchestrator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://localhost:44358/api/sync"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;clientProvider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SqliteSyncProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"advworks.db"&lt;/span&gt;&lt;span class="p"&gt;);;&lt;/span&gt;

&lt;span class="c1"&gt;// Using the IProgress&amp;lt;T&amp;gt; pattern to handle progession dring the synchronization&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;progress&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;SynchronousProgress&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ProgressArgs&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SyncStage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;:\t&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Creating an agent that will handle all the process&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SyncAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clientProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serverOrchestrator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Launch the sync process&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;s1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SynchronizeAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Write results&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadKey&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;ConsoleKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Escape&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"End"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;As you can see here, no tables are specified from the client side. Everything related to the schema is handled by the server side.&lt;/p&gt;

&lt;p&gt;Don't forget to run your web server api, before launching your sync.&lt;br&gt;
Eventually, you should have something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h3KXB7WG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/b1wf9r7ojhv3ncwx1iub.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h3KXB7WG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/b1wf9r7ojhv3ncwx1iub.png" alt="Alt Text" width="800" height="551"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you need more information on the &lt;code&gt;Dotmim.Sync&lt;/code&gt; framework, do not hesitate to reach me out on twitter &lt;a href="https://twitter.com/sebpertus"&gt;@sebpertus&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The full documentation is available here : &lt;a href="https://mimetis.github.io/Dotmim.Sync"&gt;https://mimetis.github.io/Dotmim.Sync&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The source code is hosted on Github here : &lt;a href="https://github.com/Mimetis/Dotmim.Sync"&gt;https://github.com/Mimetis/Dotmim.Sync&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy sync !&lt;/p&gt;

&lt;p&gt;Seb&lt;/p&gt;

</description>
      <category>database</category>
      <category>synchronization</category>
      <category>sql</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>How to Synchronize relational databases with Dotmim.Sync</title>
      <dc:creator>Sébastien Pertus</dc:creator>
      <pubDate>Tue, 04 Feb 2020 17:41:15 +0000</pubDate>
      <link>https://dev.to/mimetis/how-to-synchronize-relational-databases-with-dotmim-sync-5693</link>
      <guid>https://dev.to/mimetis/how-to-synchronize-relational-databases-with-dotmim-sync-5693</guid>
      <description>&lt;p&gt;This post is part of a series about &lt;a href="https://github.com/Mimetis/Dotmim.Sync" rel="noopener noreferrer"&gt;Dotmim.Sync&lt;/a&gt; on how to synchronize relations databases between a server hub and multiple client members:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://dev.to/mimetis/how-to-synchronize-relational-databases-with-dotmim-sync-5693"&gt;Part 1&lt;/a&gt;: Introduction to Dotmim.Sync: Hello Sync !&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/mimetis/how-to-synchronize-relational-databases-with-dotmim-sync-part-2-1gba"&gt;Part 2&lt;/a&gt;: Protecting your hub behind a web API, through ASP.Net Core Web Api&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  You say ... Dotmim... Sync ?
&lt;/h1&gt;

&lt;p&gt;Back in the days, Microsoft released a full C# framework to allow databases synchronization, called the &lt;strong&gt;Sync Framework&lt;/strong&gt;.&lt;br&gt;
Today, (part of) this framework is open source but it lacks a lot of features to meet current mobile development needs, and a solid cross platform compatibility (and to be honest, a better ease of implementation without any code generation and pre-work)&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/Mimetis/Dotmim.Sync" rel="noopener noreferrer"&gt;Dotmim.Sync&lt;/a&gt; framework is inspired from this old framework, without all the complications, glitches or code generation and adding some cool features.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Dotmim.Sync&lt;/code&gt; framework works on all platforms supporting &lt;strong&gt;.Net Standard 2.0&lt;/strong&gt; librairies.&lt;br&gt;
You can use it in a &lt;strong&gt;.Net Core&lt;/strong&gt; application running on Windows or Linux, or you can use it embedded in your &lt;strong&gt;Xamarin&lt;/strong&gt; application for &lt;strong&gt;iOS&lt;/strong&gt; or &lt;strong&gt;Android&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Many features are available through this framework:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multi databases support (SQL Server, MYSQL, SQLite)&lt;/li&gt;
&lt;li&gt;Conflict resolution&lt;/li&gt;
&lt;li&gt;Snapshot initialization&lt;/li&gt;
&lt;li&gt;Filters&lt;/li&gt;
&lt;li&gt;Custom serializers&lt;/li&gt;
&lt;li&gt;Mode TCP and HTTP through ASP.NET Core Web API&lt;/li&gt;
&lt;li&gt;Sync Direction (Bidirectional, DownloadOnly, UploadOnly)&lt;/li&gt;
&lt;li&gt;SQL Server only: Support of change tracking / bulk operations with TVP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And more to come :)&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Multi Databases&lt;/th&gt;
&lt;th&gt;Cross Plaform&lt;/th&gt;
&lt;th&gt;.Net Standard 2.0&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&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%2Fi%2Febitucdjb0szrk0fjg2f.png"&gt;&lt;/td&gt;
&lt;td&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%2Fi%2Fixn1otl3gj5gzw69qmsu.png"&gt;&lt;/td&gt;
&lt;td&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%2Fi%2Fjxavsazmdal2li9kpfhe.png" alt="Alt Text"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h1&gt;
  
  
  Hello Sync !
&lt;/h1&gt;

&lt;p&gt;One of the main objectives of the &lt;code&gt;Dotmim.Sync&lt;/code&gt; framework is to be able to write your first synchronization with less than 5 lines of code.&lt;/p&gt;

&lt;p&gt;Let's do it.&lt;/p&gt;

&lt;p&gt;What you need so far for your first &lt;em&gt;"Hello Sync"&lt;/em&gt; project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A SQL Server / MySQL database up and running : Use this &lt;a href="https://github.com/Mimetis/Dotmim.Sync/blob/master/CreateAdventureWorks.sql" rel="noopener noreferrer"&gt;AdventureWorks script&lt;/a&gt; if you need something for testing purpose (and all the samples will be based on this database)&lt;/li&gt;
&lt;li&gt;A blank console application on top of &lt;a href="https://dotnet.microsoft.com/download" rel="noopener noreferrer"&gt;.Net Core&lt;/a&gt; with the &lt;code&gt;Dotmim.Sync&lt;/code&gt; nuget packages installed (depending on the targeted databases)&lt;/li&gt;
&lt;/ul&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%2Fi%2F9va1g8beb64mi91gb95h.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%2Fi%2F9va1g8beb64mi91gb95h.png" alt="Dotmim.Sync nuget packages"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We're going to create a sync between a &lt;strong&gt;server&lt;/strong&gt; database hosted on &lt;strong&gt;SQL Server&lt;/strong&gt; and a &lt;strong&gt;SQLite&lt;/strong&gt; &lt;strong&gt;client&lt;/strong&gt; database.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Dotmim.Sync&lt;/code&gt; framework is built on database providers. &lt;br&gt;
For instance, if you need to sync a &lt;strong&gt;SQL Server&lt;/strong&gt; database, you will have to install the &lt;code&gt;SqlSyncProvider&lt;/code&gt; provider.&lt;br&gt;
For &lt;strong&gt;MySql&lt;/strong&gt;, use the &lt;code&gt;MySqlSyncProvider&lt;/code&gt; provider and of course for &lt;strong&gt;SQLite&lt;/strong&gt;, the &lt;code&gt;SqliteSyncProvider&lt;/code&gt; provider.&lt;br&gt;
Each provider will manage the communication between the &lt;code&gt;Dotmim.Sync&lt;/code&gt; core components and your database.&lt;br&gt;
More providers will be (hopefully) developed later (like &lt;strong&gt;Oracle&lt;/strong&gt; or &lt;strong&gt;PostgreSQL&lt;/strong&gt;)&lt;/p&gt;

&lt;p&gt;Now you have everything installed, let's go coding !&lt;/p&gt;

&lt;p&gt;We need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;SqlSyncProvider&lt;/code&gt; to communicate with the server databse.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;SqliteSyncProvider&lt;/code&gt; to communicate with the client database.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;SyncSetup&lt;/code&gt; containing the tables you want to synchronize.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;SyncAgent&lt;/code&gt; that will orchestrate the whole sync processus.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 csharp
var serverProvider = new SqlSyncProvider(GetDatabaseConnectionString("AdventureWorks"));
var clientProvider = new SqliteSyncProvider("advworks.db");

var setup = new SyncSetup("ProductCategory", "ProductModel", "Product", "Address", "Customer", "CustomerAddress", "SalesOrderHeader", "SalesOrderDetail");

var agent = new SyncAgent(clientProvider, serverProvider);

var syncContext = await agent.SynchronizeAsync(setup);
Console.WriteLine(syncContext);



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

&lt;/div&gt;

&lt;p&gt;As you can see, your &lt;code&gt;SyncAgent&lt;/code&gt; instance has references on both server side and client side, plus the tables list.&lt;br&gt;
Once initialized, just called the asynchronous method &lt;code&gt;SynchronizeAsync()&lt;/code&gt; and you're done !&lt;/p&gt;

&lt;p&gt;The result from this first run should looks like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 bash
Synchronization done.
        Total changes downloaded: 2752
        Total changes uploaded: 0
        Total conflicts: 0
        Total duration :0:0:4.280
Done


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

&lt;/div&gt;

&lt;p&gt;First synchronization done, with 5 lines of code :)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: The SQLite database did not exists before the sync process happened. &lt;br&gt;
During the first sync, the &lt;code&gt;Dotmim.Sync&lt;/code&gt; has:&lt;/p&gt;

&lt;p&gt;1) Created the SQLite database, get the schema, created all the tables, then created all the required components (One tracking table per "synced" table, three triggers on each table)&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%2Fi%2F4yr3ncahlgpupkly4otx.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%2Fi%2F4yr3ncahlgpupkly4otx.png" alt="Sqlite database configured with tracking tables and triggers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2) Get all the data from the server and applied them in the SQLite database&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%2Fi%2F4hwtzfmw60fcw5l4it1j.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%2Fi%2F4hwtzfmw60fcw5l4it1j.png" alt="Rows available in SQLite after first sync"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Hello Sync V2
&lt;/h1&gt;

&lt;p&gt;The next versin of this sample will use some nice features to get some feedbacks from your client database.&lt;/p&gt;

&lt;p&gt;As &lt;code&gt;SynchronizeAsync()&lt;/code&gt; is an async method, we can use a &lt;code&gt;IProgress&amp;lt;T&amp;gt;&lt;/code&gt; to get feedbacks during the active sync:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 csharp
var progress = new SynchronousProgress&amp;lt;ProgressArgs&amp;gt;(s =&amp;gt; Console.WriteLine($"{s.Context.SyncStage}:\t{s.Message}"));

var syncContext = await agent.SynchronizeAsync(progress);


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

&lt;/div&gt;

&lt;p&gt;And because we want to run the sync again and again, we can make a nice &lt;code&gt;do while&lt;/code&gt; loop, with a little &lt;code&gt;try catch&lt;/code&gt; to ensure the application won't crash for some reasons :)&lt;/p&gt;

&lt;p&gt;Here is the full code:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 csharp
private static async Task SynchronizeAdventureWorksAsync()
{
    var serverProvider = new SqlSyncProvider(GetDatabaseConnectionString("AdventureWorks"));
    var clientProvider = new SqliteSyncProvider("advworks.db");

    var setup = new SyncSetup("ProductCategory", "ProductModel", "Product", "Address", "Customer", "CustomerAddress", "SalesOrderHeader", "SalesOrderDetail");

    var agent = new SyncAgent(clientProvider, serverProvider);

    var progress = new SynchronousProgress&amp;lt;ProgressArgs&amp;gt;(s =&amp;gt; 
            Console.WriteLine($"{s.Context.SyncStage}:\t{s.Message}"));

    do
    {
        Console.Clear();
        Console.WriteLine("Sync Start");
        try
        {
            var syncContext = await agent.SynchronizeAsync(setu, progress);
            Console.WriteLine(syncContext);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }

    } while (Console.ReadKey().Key != ConsoleKey.Escape);
}



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

&lt;/div&gt;

&lt;p&gt;And now, before launching again, let's add a new &lt;code&gt;ProductCategory&lt;/code&gt; in the server database, and update a &lt;code&gt;product&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 sql
Use AdventureWorks;
Update Product set Name = 'HL Road Frame - Black, 58 V2' where ProductId = 680;
Insert into ProductCategory (Name) Values ('Mono wheels');


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

&lt;/div&gt;

&lt;p&gt;Then launch again the sync process, you should have this result:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 bash
Sync Start
BeginSession:   18:11:24.281
ScopeLoading:   18:11:24.410     Id:932af0e6-1083-4ec4-8b39-40453e3bc586 LastSync:04/02/2020 16:49:35 LastSyncDuration:42806712
TableChangesSelected:   18:11:24.732     ProductCategory Upserts:0 Deletes:0 TotalChanges:0
TableChangesSelected:   18:11:24.732     ProductModel Upserts:0 Deletes:0 TotalChanges:0
TableChangesSelected:   18:11:24.734     Product Upserts:0 Deletes:0 TotalChanges:0
TableChangesSelected:   18:11:24.735     Address Upserts:0 Deletes:0 TotalChanges:0
TableChangesSelected:   18:11:24.736     Customer Upserts:0 Deletes:0 TotalChanges:0
TableChangesSelected:   18:11:24.737     CustomerAddress Upserts:0 Deletes:0 TotalChanges:0
TableChangesSelected:   18:11:24.738     SalesOrderHeader Upserts:0 Deletes:0 TotalChanges:0
TableChangesSelected:   18:11:24.739     SalesOrderDetail Upserts:0 Deletes:0 TotalChanges:0
TableChangesApplied:    18:11:25.415     ProductCategory State:Modified Applied:1 Failed:0
TableChangesApplied:    18:11:25.418     Product State:Modified Applied:1 Failed:0
DatabaseChangesApplied: 18:11:25.421     Changes applied on database main: Applied: 2 Failed: 0
ScopeSaved:     18:11:25.433     Id:932af0e6-1083-4ec4-8b39-40453e3bc586 LastSync:04/02/2020 17:11:25 LastSyncDuration:11541150
EndSession:     18:11:25.434
Synchronization done.
        Total changes downloaded: 2
        Total changes uploaded: 0
        Total conflicts: 0
        Total duration :0:0:1.154


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

&lt;/div&gt;

&lt;p&gt;Based on this running application, you can now test some inserts or deletes in both databases, and see the results in your console !&lt;/p&gt;

&lt;p&gt;If you need more information on the &lt;code&gt;Dotmim.Sync&lt;/code&gt; framework, do not hesitate to reach me out on twitter &lt;a href="https://twitter.com/sebpertus" rel="noopener noreferrer"&gt;@sebpertus&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The full documentation is available here : &lt;a href="https://mimetis.github.io/Dotmim.Sync" rel="noopener noreferrer"&gt;https://mimetis.github.io/Dotmim.Sync&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The source code is hosted on Github here : &lt;a href="https://github.com/Mimetis/Dotmim.Sync" rel="noopener noreferrer"&gt;https://github.com/Mimetis/Dotmim.Sync&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy sync !&lt;/p&gt;

&lt;p&gt;Seb&lt;/p&gt;

</description>
      <category>database</category>
      <category>synchronization</category>
      <category>sql</category>
      <category>dotnet</category>
    </item>
  </channel>
</rss>
