<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Echo on WebDevStation</title>
    <link>https://webdevstation.com/tags/echo/</link>
    <description>2 articles tagged Echo — tutorials, code examples and notes from building real systems, newest first.</description>
    <generator>Hugo</generator>
    <language>en</language>
    <managingEditor>Alex</managingEditor>
    <webMaster>Alex</webMaster>
    <copyright>© 2026 WebDevStation</copyright>
    <lastBuildDate>Thu, 04 Feb 2021 17:28:00 +0000</lastBuildDate>
    <atom:link href="https://webdevstation.com/tags/echo/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>How to Show Flash Messages in Go web applications (with Echo framework)</title>
      <link>https://webdevstation.com/posts/how-to-show-flash-messages-in-go-echo/</link>
      <pubDate>Thu, 04 Feb 2021 17:28:00 +0000</pubDate>
      <author>Alex</author>
      <guid isPermaLink="true">https://webdevstation.com/posts/how-to-show-flash-messages-in-go-echo/</guid>
      <description>Learn how to implement flash messages in Go web applications using Echo framework and Gorilla Sessions to improve user experience by providing feedback after form…</description>
      <content:encoded><![CDATA[<p>When we create a web application, usually, there a need to communicate with the users to inform them about the results
of their actions. The easiest way to communicate - is to send messages. These messages might be warnings, errors, or just
informational text. In this article, we will improve the UX of our user authentication application from the <a href="https://webdevstation.com/posts/user-authentication-with-go-using-jwt-token/">previous article</a>
by adding an error flash message when the user entered a wrong password and a success message after user authorisation.</p>
<p>We are going to use cookies to store messages in-between requests. To not reinvent the wheel, we will install <a href="https://github.com/gorilla/sessions">Gorilla Sessions</a>
package.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">go</span> <span style="color:#a6e22e">get</span> <span style="color:#a6e22e">github</span>.<span style="color:#a6e22e">com</span><span style="color:#f92672">/</span><span style="color:#a6e22e">gorilla</span><span style="color:#f92672">/</span><span style="color:#a6e22e">sessions</span>
</span></span></code></pre></div><p>Next, let&rsquo;s create a <code>messages</code> package (messages/messages.go):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#f92672">package</span> <span style="color:#a6e22e">messages</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> (
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;github.com/gorilla/sessions&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;github.com/labstack/echo/v4&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Name of the cookie.</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#a6e22e">sessionName</span> = <span style="color:#e6db74">&#34;fmessages&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">getCookieStore</span>() <span style="color:#f92672">*</span><span style="color:#a6e22e">sessions</span>.<span style="color:#a6e22e">CookieStore</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">// In real-world applications, use env variables to store the session key.</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">sessionKey</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;test-session-key&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">sessions</span>.<span style="color:#a6e22e">NewCookieStore</span>([]byte(<span style="color:#a6e22e">sessionKey</span>))
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Set adds a new message into the cookie storage.</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">Set</span>(<span style="color:#a6e22e">c</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">Context</span>, <span style="color:#a6e22e">name</span>, <span style="color:#a6e22e">value</span> <span style="color:#66d9ef">string</span>) {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">session</span>, <span style="color:#a6e22e">_</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">getCookieStore</span>().<span style="color:#a6e22e">Get</span>(<span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Request</span>(), <span style="color:#a6e22e">sessionName</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">session</span>.<span style="color:#a6e22e">AddFlash</span>(<span style="color:#a6e22e">value</span>, <span style="color:#a6e22e">name</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">session</span>.<span style="color:#a6e22e">Save</span>(<span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Request</span>(), <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Response</span>())
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Get gets flash messages from the cookie storage.</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">Get</span>(<span style="color:#a6e22e">c</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">Context</span>, <span style="color:#a6e22e">name</span> <span style="color:#66d9ef">string</span>) []<span style="color:#66d9ef">string</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">session</span>, <span style="color:#a6e22e">_</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">getCookieStore</span>().<span style="color:#a6e22e">Get</span>(<span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Request</span>(), <span style="color:#a6e22e">sessionName</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">fm</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">session</span>.<span style="color:#a6e22e">Flashes</span>(<span style="color:#a6e22e">name</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">// If we have some messages.</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> len(<span style="color:#a6e22e">fm</span>) &gt; <span style="color:#ae81ff">0</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">session</span>.<span style="color:#a6e22e">Save</span>(<span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Request</span>(), <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Response</span>())
</span></span><span style="display:flex;"><span>		<span style="color:#75715e">// Initiate a strings slice to return messages.</span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">flashes</span> []<span style="color:#66d9ef">string</span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">fl</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">fm</span> {
</span></span><span style="display:flex;"><span>			<span style="color:#75715e">// Add message to the slice.</span>
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">flashes</span> = append(<span style="color:#a6e22e">flashes</span>, <span style="color:#a6e22e">fl</span>.(<span style="color:#66d9ef">string</span>))
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">flashes</span>
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>We now have a possibility to easily Set and Get flash messages. Let&rsquo;s integrate it, first, to the sign-in form, which we created in the <a href="https://webdevstation.com/posts/user-authentication-with-go-using-jwt-token/">previous article</a>.</p>
<p>I&rsquo;m going to modify <code>controllers/signin.go</code> file. Inside <code>SignIn()</code> function we can replace</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">return</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">NewHTTPError</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusUnauthorized</span>, <span style="color:#e6db74">&#34;Password is incorrect&#34;</span>)
</span></span></code></pre></div><p>with</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#a6e22e">messages</span>.<span style="color:#a6e22e">Set</span>(<span style="color:#a6e22e">c</span>, <span style="color:#e6db74">&#34;error&#34;</span>, <span style="color:#e6db74">&#34;Password is incorrect!&#34;</span>)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">return</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Redirect</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusMovedPermanently</span>, <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Echo</span>().<span style="color:#a6e22e">Reverse</span>(<span style="color:#e6db74">&#34;userSignInForm&#34;</span>))
</span></span></code></pre></div><p>And, if the password is correct, we going to set a message also:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#a6e22e">messages</span>.<span style="color:#a6e22e">Set</span>(<span style="color:#a6e22e">c</span>, <span style="color:#e6db74">&#34;message&#34;</span>, <span style="color:#e6db74">&#34;Password is correct, you have been authenticated!&#34;</span>)
</span></span></code></pre></div><p>The final <code>SignIn()</code> function will look like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#75715e">// SignIn will be executed after SignInForm submission.</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">SignIn</span>() <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">HandlerFunc</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">c</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">Context</span>) <span style="color:#66d9ef">error</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#75715e">// Load our &#34;test&#34; user.</span>
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">storedUser</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">user</span>.<span style="color:#a6e22e">LoadTestUser</span>()
</span></span><span style="display:flex;"><span>		<span style="color:#75715e">// Initiate a new User struct.</span>
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">u</span> <span style="color:#f92672">:=</span> new(<span style="color:#a6e22e">user</span>.<span style="color:#a6e22e">User</span>)
</span></span><span style="display:flex;"><span>		<span style="color:#75715e">// Parse the submitted data and fill the User struct with the data from the SignIn form.</span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Bind</span>(<span style="color:#a6e22e">u</span>); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">NewHTTPError</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusInternalServerError</span>, <span style="color:#a6e22e">err</span>.<span style="color:#a6e22e">Error</span>())
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>		<span style="color:#75715e">// Compare the stored hashed password, with the hashed version of the password that was received</span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">bcrypt</span>.<span style="color:#a6e22e">CompareHashAndPassword</span>([]byte(<span style="color:#a6e22e">storedUser</span>.<span style="color:#a6e22e">Password</span>), []byte(<span style="color:#a6e22e">u</span>.<span style="color:#a6e22e">Password</span>)); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>			<span style="color:#75715e">// If the two passwords don&#39;t match, set a message and reload the page.</span>
</span></span><span style="display:flex;"><span>            <span style="color:#a6e22e">messages</span>.<span style="color:#a6e22e">Set</span>(<span style="color:#a6e22e">c</span>, <span style="color:#e6db74">&#34;error&#34;</span>, <span style="color:#e6db74">&#34;Password is incorrect!&#34;</span>)
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Redirect</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusMovedPermanently</span>, <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Echo</span>().<span style="color:#a6e22e">Reverse</span>(<span style="color:#e6db74">&#34;userSignInForm&#34;</span>))
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>		<span style="color:#75715e">// If password is correct, generate tokens and set cookies.</span>
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">auth</span>.<span style="color:#a6e22e">GenerateTokensAndSetCookies</span>(<span style="color:#a6e22e">storedUser</span>, <span style="color:#a6e22e">c</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">NewHTTPError</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusUnauthorized</span>, <span style="color:#e6db74">&#34;Token is incorrect&#34;</span>)
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">messages</span>.<span style="color:#a6e22e">Set</span>(<span style="color:#a6e22e">c</span>, <span style="color:#e6db74">&#34;message&#34;</span>, <span style="color:#e6db74">&#34;Password is correct, you have been authenticated!&#34;</span>)
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Redirect</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusMovedPermanently</span>, <span style="color:#e6db74">&#34;/admin&#34;</span>)
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Once we set messages, we need to display them.</p>
<p>First, I will add message displaying logic to the SignIn form. We need to modify <code>SignInForm()</code> function inside <code>controllers/signin.go</code>, by adding additional data with messages to the template execution function:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#a6e22e">tmpl</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">template</span>.<span style="color:#a6e22e">ParseFiles</span>(<span style="color:#a6e22e">path</span>.<span style="color:#a6e22e">Join</span>(<span style="color:#e6db74">&#34;templates&#34;</span>, <span style="color:#e6db74">&#34;signIn.html&#34;</span>), <span style="color:#a6e22e">path</span>.<span style="color:#a6e22e">Join</span>(<span style="color:#e6db74">&#34;templates&#34;</span>, <span style="color:#e6db74">&#34;messages.html&#34;</span>))
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">data</span> <span style="color:#f92672">:=</span> make(<span style="color:#66d9ef">map</span>[<span style="color:#66d9ef">string</span>]<span style="color:#66d9ef">interface</span>{})
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">data</span>[<span style="color:#e6db74">&#34;errors&#34;</span>] = <span style="color:#a6e22e">messages</span>.<span style="color:#a6e22e">Get</span>(<span style="color:#a6e22e">c</span>, <span style="color:#e6db74">&#34;error&#34;</span>)
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">tmpl</span>.<span style="color:#a6e22e">Execute</span>(<span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Response</span>().<span style="color:#a6e22e">Writer</span>, <span style="color:#a6e22e">data</span>);
</span></span></code></pre></div><p>The final <code>SignInForm()</code> function will look like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#75715e">// SignInForm responsible for signIn Form rendering.</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">SignInForm</span>() <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">HandlerFunc</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">c</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">Context</span>) <span style="color:#66d9ef">error</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">tmpl</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">template</span>.<span style="color:#a6e22e">ParseFiles</span>(<span style="color:#a6e22e">path</span>.<span style="color:#a6e22e">Join</span>(<span style="color:#e6db74">&#34;templates&#34;</span>, <span style="color:#e6db74">&#34;signIn.html&#34;</span>), <span style="color:#a6e22e">path</span>.<span style="color:#a6e22e">Join</span>(<span style="color:#e6db74">&#34;templates&#34;</span>, <span style="color:#e6db74">&#34;messages.html&#34;</span>))
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">data</span> <span style="color:#f92672">:=</span> make(<span style="color:#66d9ef">map</span>[<span style="color:#66d9ef">string</span>]<span style="color:#66d9ef">interface</span>{})
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">data</span>[<span style="color:#e6db74">&#34;errors&#34;</span>] = <span style="color:#a6e22e">messages</span>.<span style="color:#a6e22e">Get</span>(<span style="color:#a6e22e">c</span>, <span style="color:#e6db74">&#34;error&#34;</span>)
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">NewHTTPError</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusInternalServerError</span>, <span style="color:#a6e22e">err</span>.<span style="color:#a6e22e">Error</span>())
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">tmpl</span>.<span style="color:#a6e22e">Execute</span>(<span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Response</span>().<span style="color:#a6e22e">Writer</span>, <span style="color:#a6e22e">data</span>); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">NewHTTPError</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusInternalServerError</span>, <span style="color:#a6e22e">err</span>.<span style="color:#a6e22e">Error</span>())
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>As you probably noticed, we introduced <code>messages.html</code> to the <code>template.ParseFiles()</code> function. There we will control how to visualize messages. Let&rsquo;s add this template inside <code>templates</code> folder:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>{{ define &#34;messages&#34; }}
</span></span><span style="display:flex;"><span>  {{ if index . &#34;errors&#34; }}
</span></span><span style="display:flex;"><span>    &lt;<span style="color:#f92672">div</span> <span style="color:#a6e22e">class</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;errors&#34;</span> <span style="color:#a6e22e">style</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;background: darksalmon; padding: 10px;&#34;</span>&gt;
</span></span><span style="display:flex;"><span>        {{ range index . &#34;errors&#34; }}
</span></span><span style="display:flex;"><span>        &lt;<span style="color:#f92672">p</span>&gt;{{ . }}&lt;/<span style="color:#f92672">p</span>&gt;
</span></span><span style="display:flex;"><span>        {{ end }}
</span></span><span style="display:flex;"><span>    &lt;/<span style="color:#f92672">div</span>&gt;
</span></span><span style="display:flex;"><span>  {{ end }}
</span></span><span style="display:flex;"><span>  {{ if index . &#34;messages&#34; }}
</span></span><span style="display:flex;"><span>    &lt;<span style="color:#f92672">div</span> <span style="color:#a6e22e">class</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;messages&#34;</span> <span style="color:#a6e22e">style</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;background: darkseagreen; padding: 10px;&#34;</span>&gt;
</span></span><span style="display:flex;"><span>        {{ range index . &#34;messages&#34; }}
</span></span><span style="display:flex;"><span>        &lt;<span style="color:#f92672">p</span>&gt;{{ . }}&lt;/<span style="color:#f92672">p</span>&gt;
</span></span><span style="display:flex;"><span>        {{ end }}
</span></span><span style="display:flex;"><span>    &lt;/<span style="color:#f92672">div</span>&gt;
</span></span><span style="display:flex;"><span>  {{ end }}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>{{ end }}
</span></span></code></pre></div><p>Next, we need to add the reference to the <code>messages</code> template inside <code>signIn.html</code> and <code>admin.html</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span>{{ <span style="color:#a6e22e">template</span> <span style="color:#e6db74">&#34;messages&#34;</span> . }}
</span></span></code></pre></div><p>Now, we can try how does it work.</p>
<p>Let&rsquo;s run the server <code>go run main.go</code> and go to the <code>/user/signin</code> path. When we submit the form with the wrong password, we should see this:
<img src="/images/0221/error.png" alt="Error Message" title="Error Message"></p>
<p>When a password is correct, we will be redirected to the <code>/admin</code> path with the message:
<img src="/images/0221/success.png" alt="Success Message" title="Success Message"></p>
<p>In this example, I was using the Echo framework, but it will be super easy to modify the code for your specific use-case.</p>
<p>The complete source code you can find <a href="https://github.com/alexsergivan/blog-examples/tree/master/flashmessages">here</a>.</p>
<p>Flash messages usually appear right after a login or a form post, so the natural companion pieces are <a href="/posts/user-authentication-with-go-using-jwt-token/">user authentication in Go Echo with JWT</a> and, for the layer that wraps every handler, <a href="/posts/go-middleware-example/">the Go middleware example</a>.</p>]]></content:encoded>
      <category>Go Programming</category>
      <category>Web Development</category>
    </item>
    <item>
      <title>User Authentication in Go Echo with JWT</title>
      <link>https://webdevstation.com/posts/user-authentication-with-go-using-jwt-token/</link>
      <pubDate>Thu, 28 Jan 2021 18:05:51 +0000</pubDate>
      <author>Alex</author>
      <guid isPermaLink="true">https://webdevstation.com/posts/user-authentication-with-go-using-jwt-token/</guid>
      <description>Learn how to implement secure user authentication in Go using JWT (JSON Web Tokens) with the Echo framework. This step-by-step guide covers token creation,…</description>
      <content:encoded><![CDATA[<p>In this article, we will build a simple user authentication functionality using JWT (JSON Web Token).
In the examples, I&rsquo;m going to use a Go <a href="https://echo.labstack.com/">Echo</a> framework. This will allow us
to avoid writing some boilerplate code.</p>
<p>If you are not familiar with a JWT theory, please refer to <a href="https://jwt.io/introduction/">this resource</a>.</p>
<p>I believe that the easiest way to understand how to work with JWT authentication is by solving a real-world problem.
Let&rsquo;s say, that we have a website with an administration section, that should be accessible only by authenticated users, by providing some credentials. If authentication was successful, the user can access the administration section. If the user is inactive during a defined period of time, we should log him out from the system.</p>
<p>In the beginning, I&rsquo;m going to create a <code>main.go</code> file with initialization of the web server and some routers:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> (
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;fmt&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;github.com/alexsergivan/blog-examples/authentication/auth&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;github.com/alexsergivan/blog-examples/authentication/controllers&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;github.com/labstack/echo/v4&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;github.com/labstack/echo/v4/middleware&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;net/http&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">e</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">New</span>()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// Defining of the admin router group.</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">adminGroup</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">Group</span>(<span style="color:#e6db74">&#34;/admin&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// Router for &#34;/admin&#34; path.</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">adminGroup</span>.<span style="color:#a6e22e">GET</span>(<span style="color:#e6db74">&#34;&#34;</span>, <span style="color:#a6e22e">controllers</span>.<span style="color:#a6e22e">Admin</span>())
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// Starting the server.</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">Logger</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">Start</span>(<span style="color:#e6db74">&#34;:8777&#34;</span>))
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>And controllers/admin.go:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#f92672">package</span> <span style="color:#a6e22e">controllers</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> (
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;fmt&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;github.com/labstack/echo/v4&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;net/http&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">Admin</span>() <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">HandlerFunc</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">c</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">Context</span>) <span style="color:#66d9ef">error</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">String</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusOK</span>, <span style="color:#e6db74">&#34;Hi, you have access!&#34;</span>)
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>If you run this code and go to <code>http://localhost:8777/admin</code>, you will access this page without any authentication.
Let&rsquo;s protect this path, by adding a JWT authentication.</p>
<p>First, what I&rsquo;m going to create - it&rsquo;s an <code>auth</code> package, where we will keep all JWT related logic.
Please refer to the code below with added explanatory comments:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#f92672">package</span> <span style="color:#a6e22e">auth</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> (
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;github.com/alexsergivan/blog-examples/authentication/user&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;github.com/labstack/echo/v4&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;net/http&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;time&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;github.com/dgrijalva/jwt-go&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> (
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">accessTokenCookieName</span>  = <span style="color:#e6db74">&#34;access-token&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// Just for the demo purpose, I declared a secret here. In the real-world application, you might need to get it from the env variables.</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">jwtSecretKey</span> = <span style="color:#e6db74">&#34;some-secret-key&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">GetJWTSecret</span>() <span style="color:#66d9ef">string</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">jwtSecretKey</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Create a struct that will be encoded to a JWT.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// We add jwt.StandardClaims as an embedded type, to provide fields like expiry time.</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Claims</span> <span style="color:#66d9ef">struct</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Name</span>  <span style="color:#66d9ef">string</span> <span style="color:#e6db74">`json:&#34;name&#34;`</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">jwt</span>.<span style="color:#a6e22e">StandardClaims</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// GenerateTokensAndSetCookies generates jwt token and saves it to the http-only cookie.</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">GenerateTokensAndSetCookies</span>(<span style="color:#a6e22e">user</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">user</span>.<span style="color:#a6e22e">User</span>, <span style="color:#a6e22e">c</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">Context</span>) <span style="color:#66d9ef">error</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">accessToken</span>, <span style="color:#a6e22e">exp</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">generateAccessToken</span>(<span style="color:#a6e22e">user</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">err</span>
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">setTokenCookie</span>(<span style="color:#a6e22e">accessTokenCookieName</span>, <span style="color:#a6e22e">accessToken</span>, <span style="color:#a6e22e">exp</span>, <span style="color:#a6e22e">c</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">setUserCookie</span>(<span style="color:#a6e22e">user</span>, <span style="color:#a6e22e">exp</span>, <span style="color:#a6e22e">c</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">generateAccessToken</span>(<span style="color:#a6e22e">user</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">user</span>.<span style="color:#a6e22e">User</span>) (<span style="color:#66d9ef">string</span>, <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Time</span>, <span style="color:#66d9ef">error</span>) {
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">// Declare the expiration time of the token (1h).</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">expirationTime</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Now</span>().<span style="color:#a6e22e">Add</span>(<span style="color:#ae81ff">1</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Hour</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">generateToken</span>(<span style="color:#a6e22e">user</span>, <span style="color:#a6e22e">expirationTime</span>, []byte(<span style="color:#a6e22e">GetJWTSecret</span>()))
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Pay attention to this function. It holds the main JWT token generation logic.</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">generateToken</span>(<span style="color:#a6e22e">user</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">user</span>.<span style="color:#a6e22e">User</span>, <span style="color:#a6e22e">expirationTime</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Time</span>, <span style="color:#a6e22e">secret</span> []<span style="color:#66d9ef">byte</span>) (<span style="color:#66d9ef">string</span>, <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Time</span>, <span style="color:#66d9ef">error</span>) {
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">// Create the JWT claims, which includes the username and expiry time.</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">claims</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">Claims</span>{
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">Name</span>:  <span style="color:#a6e22e">user</span>.<span style="color:#a6e22e">Name</span>,
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">StandardClaims</span>: <span style="color:#a6e22e">jwt</span>.<span style="color:#a6e22e">StandardClaims</span>{
</span></span><span style="display:flex;"><span>			<span style="color:#75715e">// In JWT, the expiry time is expressed as unix milliseconds.</span>
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">ExpiresAt</span>: <span style="color:#a6e22e">expirationTime</span>.<span style="color:#a6e22e">Unix</span>(),
</span></span><span style="display:flex;"><span>		},
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">// Declare the token with the HS256 algorithm used for signing, and the claims.</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">token</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">jwt</span>.<span style="color:#a6e22e">NewWithClaims</span>(<span style="color:#a6e22e">jwt</span>.<span style="color:#a6e22e">SigningMethodHS256</span>, <span style="color:#a6e22e">claims</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">// Create the JWT string.</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">tokenString</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">token</span>.<span style="color:#a6e22e">SignedString</span>(<span style="color:#a6e22e">secret</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;&#34;</span>, <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Now</span>(), <span style="color:#a6e22e">err</span>
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">tokenString</span>, <span style="color:#a6e22e">expirationTime</span>, <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Here we are creating a new cookie, which will store the valid JWT token.</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">setTokenCookie</span>(<span style="color:#a6e22e">name</span>, <span style="color:#a6e22e">token</span> <span style="color:#66d9ef">string</span>, <span style="color:#a6e22e">expiration</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Time</span>, <span style="color:#a6e22e">c</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">Context</span>) {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">cookie</span> <span style="color:#f92672">:=</span> new(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Cookie</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">cookie</span>.<span style="color:#a6e22e">Name</span> = <span style="color:#a6e22e">name</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">cookie</span>.<span style="color:#a6e22e">Value</span> = <span style="color:#a6e22e">token</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">cookie</span>.<span style="color:#a6e22e">Expires</span> = <span style="color:#a6e22e">expiration</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">cookie</span>.<span style="color:#a6e22e">Path</span> = <span style="color:#e6db74">&#34;/&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// Http-only helps mitigate the risk of client side script accessing the protected cookie.</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">cookie</span>.<span style="color:#a6e22e">HttpOnly</span> = <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">SetCookie</span>(<span style="color:#a6e22e">cookie</span>)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Purpose of this cookie is to store the user&#39;s name.</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">setUserCookie</span>(<span style="color:#a6e22e">user</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">user</span>.<span style="color:#a6e22e">User</span>, <span style="color:#a6e22e">expiration</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Time</span>, <span style="color:#a6e22e">c</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">Context</span>) {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">cookie</span> <span style="color:#f92672">:=</span> new(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Cookie</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">cookie</span>.<span style="color:#a6e22e">Name</span> = <span style="color:#e6db74">&#34;user&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">cookie</span>.<span style="color:#a6e22e">Value</span> = <span style="color:#a6e22e">user</span>.<span style="color:#a6e22e">Name</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">cookie</span>.<span style="color:#a6e22e">Expires</span> = <span style="color:#a6e22e">expiration</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">cookie</span>.<span style="color:#a6e22e">Path</span> = <span style="color:#e6db74">&#34;/&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">SetCookie</span>(<span style="color:#a6e22e">cookie</span>)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// JWTErrorChecker will be executed when user try to access a protected path.</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">JWTErrorChecker</span>(<span style="color:#a6e22e">err</span> <span style="color:#66d9ef">error</span>, <span style="color:#a6e22e">c</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">Context</span>) <span style="color:#66d9ef">error</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// Redirects to the signIn form.</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Redirect</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusMovedPermanently</span>, <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Echo</span>().<span style="color:#a6e22e">Reverse</span>(<span style="color:#e6db74">&#34;userSignInForm&#34;</span>))
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>After finishing the main JWT token functionality, let&rsquo;s add the SignIn controllers, which will handle user authentication.
First, we need to add the new routers inside <code>main()</code> function:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span>    <span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">GET</span>(<span style="color:#e6db74">&#34;/user/signin&#34;</span>, <span style="color:#a6e22e">controllers</span>.<span style="color:#a6e22e">SignInForm</span>()).<span style="color:#a6e22e">Name</span> = <span style="color:#e6db74">&#34;userSignInForm&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">POST</span>(<span style="color:#e6db74">&#34;/user/signin&#34;</span>, <span style="color:#a6e22e">controllers</span>.<span style="color:#a6e22e">SignIn</span>())
</span></span></code></pre></div><p>In the code below I created a <code>user</code> package with the user structure and a function that loads a dummy user from imaginary database. We gonna need it in our controllers to process and validate user data.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#f92672">package</span> <span style="color:#a6e22e">user</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> <span style="color:#e6db74">&#34;golang.org/x/crypto/bcrypt&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">User</span> <span style="color:#66d9ef">struct</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Password</span> <span style="color:#66d9ef">string</span> <span style="color:#e6db74">`json:&#34;password&#34; form:&#34;password&#34;`</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Name</span> <span style="color:#66d9ef">string</span> <span style="color:#e6db74">`json:&#34;name&#34; form:&#34;name&#34;`</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">LoadTestUser</span>() <span style="color:#f92672">*</span><span style="color:#a6e22e">User</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// Just for demonstration purpose, we create a user with the encrypted &#34;test&#34; password.</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// In real-world applications, you might load the user from the database by specific parameters (email, username, etc.)</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">hashedPassword</span>, <span style="color:#a6e22e">_</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">bcrypt</span>.<span style="color:#a6e22e">GenerateFromPassword</span>([]byte(<span style="color:#e6db74">&#34;test&#34;</span>), <span style="color:#ae81ff">8</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">User</span>{<span style="color:#a6e22e">Password</span>: string(<span style="color:#a6e22e">hashedPassword</span>), <span style="color:#a6e22e">Name</span>: <span style="color:#e6db74">&#34;Test user&#34;</span>}
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>After this, we will create a <code>controllers</code> package, where we add <code>SignInForm()</code> and <code>SignIn()</code> functions:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#f92672">package</span> <span style="color:#a6e22e">controllers</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> (
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;github.com/alexsergivan/blog-examples/authentication/auth&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;github.com/alexsergivan/blog-examples/authentication/user&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;github.com/labstack/echo/v4&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;golang.org/x/crypto/bcrypt&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;html/template&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;net/http&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;path&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// SignInForm responsible for signIn Form rendering.</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">SignInForm</span>() <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">HandlerFunc</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">c</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">Context</span>) <span style="color:#66d9ef">error</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">fp</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">path</span>.<span style="color:#a6e22e">Join</span>(<span style="color:#e6db74">&#34;templates&#34;</span>, <span style="color:#e6db74">&#34;signIn.html&#34;</span>)
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">tmpl</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">template</span>.<span style="color:#a6e22e">ParseFiles</span>(<span style="color:#a6e22e">fp</span>)
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">NewHTTPError</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusInternalServerError</span>, <span style="color:#a6e22e">err</span>.<span style="color:#a6e22e">Error</span>())
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">tmpl</span>.<span style="color:#a6e22e">Execute</span>(<span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Response</span>().<span style="color:#a6e22e">Writer</span>, <span style="color:#66d9ef">nil</span>); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">NewHTTPError</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusInternalServerError</span>, <span style="color:#a6e22e">err</span>.<span style="color:#a6e22e">Error</span>())
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// SignIn will be executed after SignInForm submission.</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">SignIn</span>() <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">HandlerFunc</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">c</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">Context</span>) <span style="color:#66d9ef">error</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// Load our &#34;test&#34; user.</span>
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">storedUser</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">user</span>.<span style="color:#a6e22e">LoadTestUser</span>()
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// Initiate a new User struct.</span>
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">u</span> <span style="color:#f92672">:=</span> new(<span style="color:#a6e22e">user</span>.<span style="color:#a6e22e">User</span>)
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// Parse the submitted data and fill the User struct with the data from the SignIn form.</span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Bind</span>(<span style="color:#a6e22e">u</span>); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">NewHTTPError</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusInternalServerError</span>, <span style="color:#a6e22e">err</span>.<span style="color:#a6e22e">Error</span>())
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>		<span style="color:#75715e">// Compare the stored hashed password, with the hashed version of the password that was received.</span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">bcrypt</span>.<span style="color:#a6e22e">CompareHashAndPassword</span>([]byte(<span style="color:#a6e22e">storedUser</span>.<span style="color:#a6e22e">Password</span>), []byte(<span style="color:#a6e22e">u</span>.<span style="color:#a6e22e">Password</span>)); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>			<span style="color:#75715e">// If the two passwords don&#39;t match, return a 401 status.</span>
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">NewHTTPError</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusUnauthorized</span>, <span style="color:#e6db74">&#34;Password is incorrect&#34;</span>)
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// If password is correct, generate tokens and set cookies.</span>
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">auth</span>.<span style="color:#a6e22e">GenerateTokensAndSetCookies</span>(<span style="color:#a6e22e">storedUser</span>, <span style="color:#a6e22e">c</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">NewHTTPError</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusUnauthorized</span>, <span style="color:#e6db74">&#34;Token is incorrect&#34;</span>)
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Redirect</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusMovedPermanently</span>, <span style="color:#e6db74">&#34;/admin&#34;</span>)
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Now, in the <code>/templates</code> folder we need to create a <code>signIn.html</code> template with the simple SignIn form:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span><span style="color:#75715e">&lt;!DOCTYPE html&gt;</span>
</span></span><span style="display:flex;"><span>&lt;<span style="color:#f92672">html</span> <span style="color:#a6e22e">lang</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;en&#34;</span>&gt;
</span></span><span style="display:flex;"><span>  &lt;<span style="color:#f92672">form</span> <span style="color:#a6e22e">class</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;w-full&#34;</span> <span style="color:#a6e22e">method</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;post&#34;</span> <span style="color:#a6e22e">action</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;/user/signin&#34;</span>&gt;
</span></span><span style="display:flex;"><span>    &lt;<span style="color:#f92672">label</span> <span style="color:#a6e22e">for</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;password&#34;</span>&gt;Password:&lt;/<span style="color:#f92672">label</span>&gt;
</span></span><span style="display:flex;"><span>    &lt;<span style="color:#f92672">input</span> <span style="color:#a6e22e">type</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;password&#34;</span> <span style="color:#a6e22e">id</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;password&#34;</span> <span style="color:#a6e22e">name</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;password&#34;</span>&gt;
</span></span><span style="display:flex;"><span>    &lt;<span style="color:#f92672">button</span> <span style="color:#a6e22e">type</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;submit&#34;</span>&gt;Sign In&lt;/<span style="color:#f92672">button</span>&gt;
</span></span><span style="display:flex;"><span>  &lt;/<span style="color:#f92672">form</span>&gt;
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#f92672">html</span>&gt;
</span></span></code></pre></div><p>Let&rsquo;s also modify the <code>admin</code> controller in <code>controllers/admin.go</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#f92672">package</span> <span style="color:#a6e22e">controllers</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> (
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;fmt&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;github.com/labstack/echo/v4&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;net/http&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">Admin</span>() <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">HandlerFunc</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">c</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">Context</span>) <span style="color:#66d9ef">error</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// Gets user cookie.</span>
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">userCookie</span>, <span style="color:#a6e22e">_</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Cookie</span>(<span style="color:#e6db74">&#34;user&#34;</span>)
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">String</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusOK</span>, <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Sprintf</span>(<span style="color:#e6db74">&#34;Hi, %s! You have been authenticated!&#34;</span>, <span style="color:#a6e22e">userCookie</span>.<span style="color:#a6e22e">Value</span>))
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>And finally, we need to add a JWT Middleware to the adminGroup path inside the <code>main()</code> function:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#75715e">// Read more about JWT Middleware here: https://echo.labstack.com/middleware/jwt</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">adminGroup</span>.<span style="color:#a6e22e">Use</span>(<span style="color:#a6e22e">middleware</span>.<span style="color:#a6e22e">JWTWithConfig</span>(<span style="color:#a6e22e">middleware</span>.<span style="color:#a6e22e">JWTConfig</span>{
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">Claims</span>:                  <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">auth</span>.<span style="color:#a6e22e">Claims</span>{},
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">SigningKey</span>:              []byte(<span style="color:#a6e22e">auth</span>.<span style="color:#a6e22e">GetJWTSecret</span>()),
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">TokenLookup</span>:             <span style="color:#e6db74">&#34;cookie:access-token&#34;</span>, <span style="color:#75715e">// &#34;&lt;source&gt;:&lt;name&gt;&#34;</span>
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">ErrorHandlerWithContext</span>: <span style="color:#a6e22e">auth</span>.<span style="color:#a6e22e">JWTErrorChecker</span>,
</span></span><span style="display:flex;"><span>    }))
</span></span></code></pre></div><p>After that, execute <code>go run main.go</code>, to run the server, and go to <code>/admin</code> path. You will be redirected to the <code>/user/signin</code> path, because you need to be authenticated to access it. That is exactly what we need! Just enter <code>test</code> password and click on <code>Sign In</code> button. You will see this message: <code>Hi, Test user! You have been authenticated!</code> Awesome!</p>
<p>As you remember earlier, we set expiration time for the token: <code>expirationTime := time.Now().Add(1 * time.Hour)</code> It means, that after 1 hour user will be automatically logged-out. This is something what we want to prevent, especially if user is still active and doing some work on our resource.
This is possible to solve, by introducing a Refresh token. This token will have a much longer life-time and will be used for refreshing the Access token.
Let&rsquo;s modify our previous code.</p>
<p>First of all, we need to declare a secret for the Refresh token and cookie name to store the generated JWT. I will store it in a constant, but in the real-world applications please use environment variables for security reasons.</p>
<p>Inside <code>auth</code> package (/auth/auth.go) we need to add these modifications:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">const</span> (
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">accessTokenCookieName</span>  = <span style="color:#e6db74">&#34;access-token&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">refreshTokenCookieName</span> = <span style="color:#e6db74">&#34;refresh-token&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">jwtSecretKey</span> = <span style="color:#e6db74">&#34;some-secret-key&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">jwtRefreshSecretKey</span> = <span style="color:#e6db74">&#34;some-refresh-secret-key&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">GetRefreshJWTSecret</span>() <span style="color:#66d9ef">string</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">jwtRefreshSecretKey</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">GenerateTokensAndSetCookies</span>(<span style="color:#a6e22e">user</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">user</span>.<span style="color:#a6e22e">User</span>, <span style="color:#a6e22e">c</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">Context</span>) <span style="color:#66d9ef">error</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">accessToken</span>, <span style="color:#a6e22e">exp</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">generateAccessToken</span>(<span style="color:#a6e22e">user</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">err</span>
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">setTokenCookie</span>(<span style="color:#a6e22e">accessTokenCookieName</span>, <span style="color:#a6e22e">accessToken</span>, <span style="color:#a6e22e">exp</span>, <span style="color:#a6e22e">c</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">setUserCookie</span>(<span style="color:#a6e22e">user</span>, <span style="color:#a6e22e">exp</span>, <span style="color:#a6e22e">c</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// We generate here a new refresh token and saving it to the cookie.</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">refreshToken</span>, <span style="color:#a6e22e">exp</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">generateRefreshToken</span>(<span style="color:#a6e22e">user</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">err</span>
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">setTokenCookie</span>(<span style="color:#a6e22e">refreshTokenCookieName</span>, <span style="color:#a6e22e">refreshToken</span>, <span style="color:#a6e22e">exp</span>, <span style="color:#a6e22e">c</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">generateRefreshToken</span>(<span style="color:#a6e22e">user</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">user</span>.<span style="color:#a6e22e">User</span>) (<span style="color:#66d9ef">string</span>, <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Time</span>, <span style="color:#66d9ef">error</span>) {
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">// Declare the expiration time of the token - 24 hours.</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">expirationTime</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Now</span>().<span style="color:#a6e22e">Add</span>(<span style="color:#ae81ff">24</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Hour</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">generateToken</span>(<span style="color:#a6e22e">user</span>, <span style="color:#a6e22e">expirationTime</span>, []byte(<span style="color:#a6e22e">GetRefreshJWTSecret</span>()))
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>At this point, when the user is signing-in, we generate 2 tokens: access and refresh. We still need to add logic for updating the access token, if the user is still active. For that, we can add a middleware, where we can check how much time is left for the user&rsquo;s access token, and if this time is less than some period of time (in this example it&rsquo;s 15 mins) we can generate the new tokens, by providing a valid refresh token.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#75715e">// TokenRefresherMiddleware middleware, which refreshes JWT tokens if the access token is about to expire.</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">TokenRefresherMiddleware</span>(<span style="color:#a6e22e">next</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">HandlerFunc</span>) <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">HandlerFunc</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">c</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">Context</span>) <span style="color:#66d9ef">error</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// If the user is not authenticated (no user token data in the context), don&#39;t do anything.</span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Get</span>(<span style="color:#e6db74">&#34;user&#34;</span>) <span style="color:#f92672">==</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">next</span>(<span style="color:#a6e22e">c</span>)
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// Gets user token from the context.</span>
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">u</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Get</span>(<span style="color:#e6db74">&#34;user&#34;</span>).(<span style="color:#f92672">*</span><span style="color:#a6e22e">jwt</span>.<span style="color:#a6e22e">Token</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">claims</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">u</span>.<span style="color:#a6e22e">Claims</span>.(<span style="color:#f92672">*</span><span style="color:#a6e22e">Claims</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#75715e">// We ensure that a new token is not issued until enough time has elapsed.</span>
</span></span><span style="display:flex;"><span>		<span style="color:#75715e">// In this case, a new token will only be issued if the old token is within</span>
</span></span><span style="display:flex;"><span>		<span style="color:#75715e">// 15 mins of expiry.</span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Unix</span>(<span style="color:#a6e22e">claims</span>.<span style="color:#a6e22e">ExpiresAt</span>, <span style="color:#ae81ff">0</span>).<span style="color:#a6e22e">Sub</span>(<span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Now</span>()) &lt; <span style="color:#ae81ff">15</span><span style="color:#f92672">*</span><span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Minute</span> {
</span></span><span style="display:flex;"><span>            <span style="color:#75715e">// Gets the refresh token from the cookie.</span>
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">rc</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Cookie</span>(<span style="color:#a6e22e">refreshTokenCookieName</span>)
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">==</span> <span style="color:#66d9ef">nil</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">rc</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>                <span style="color:#75715e">// Parses token and checks if it valid.</span>
</span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">tkn</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">jwt</span>.<span style="color:#a6e22e">ParseWithClaims</span>(<span style="color:#a6e22e">rc</span>.<span style="color:#a6e22e">Value</span>, <span style="color:#a6e22e">claims</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">token</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">jwt</span>.<span style="color:#a6e22e">Token</span>) (<span style="color:#66d9ef">interface</span>{}, <span style="color:#66d9ef">error</span>) {
</span></span><span style="display:flex;"><span>					<span style="color:#66d9ef">return</span> []byte(<span style="color:#a6e22e">GetRefreshJWTSecret</span>()), <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>				})
</span></span><span style="display:flex;"><span>				<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>					<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">==</span> <span style="color:#a6e22e">jwt</span>.<span style="color:#a6e22e">ErrSignatureInvalid</span> {
</span></span><span style="display:flex;"><span>						<span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Response</span>().<span style="color:#a6e22e">Writer</span>.<span style="color:#a6e22e">WriteHeader</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusUnauthorized</span>)
</span></span><span style="display:flex;"><span>					}
</span></span><span style="display:flex;"><span>				}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>				<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">tkn</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">tkn</span>.<span style="color:#a6e22e">Valid</span> {
</span></span><span style="display:flex;"><span>                    <span style="color:#75715e">// If everything is good, update tokens.</span>
</span></span><span style="display:flex;"><span>					<span style="color:#a6e22e">_</span> = <span style="color:#a6e22e">GenerateTokensAndSetCookies</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">user</span>.<span style="color:#a6e22e">User</span>{
</span></span><span style="display:flex;"><span>						<span style="color:#a6e22e">Name</span>:  <span style="color:#a6e22e">claims</span>.<span style="color:#a6e22e">Name</span>,
</span></span><span style="display:flex;"><span>					}, <span style="color:#a6e22e">c</span>)
</span></span><span style="display:flex;"><span>				}
</span></span><span style="display:flex;"><span>			}
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">next</span>(<span style="color:#a6e22e">c</span>)
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>And finally, we have to attach our middleware to the <code>adminGroup</code> router inside the <code>main()</code> function:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span>	<span style="color:#a6e22e">adminGroup</span>.<span style="color:#a6e22e">Use</span>(<span style="color:#a6e22e">auth</span>.<span style="color:#a6e22e">TokenRefresherMiddleware</span>)
</span></span></code></pre></div><p>You can run the server again and experiment, how does it work. As an example, you can change the access token lifetime to 1min and investigate how the jwt cookies behave.</p>
<p>That was pretty much it. I hope this article was helpful for you.</p>
<p>The complete source code you can found <a href="https://github.com/alexsergivan/blog-examples/tree/master/authentication">here</a>.</p>
<p>Authentication is only the first half. For deciding what an authenticated user is allowed to reach, see <a href="/posts/how-to-control-router-access-permissions-in-go-web-apps/">how to control router access permissions in Go web apps</a>; for keeping one client from consuming everyone&rsquo;s capacity, <a href="/posts/rate-limiting-go-apis/">rate limiting Go APIs</a>. And to tell the user what actually happened after a failed login, <a href="/posts/how-to-show-flash-messages-in-go-echo/">how to show flash messages in Go web applications</a>.</p>]]></content:encoded>
      <category>Go Programming</category>
      <category>Web Development</category>
      <category>Security</category>
    </item>
  </channel>
</rss>
