<p>Today, let's have a look at how you can use <a href="http://jwt.io">JWT Authentication</a> in <a href="http://golang.org">Go</a>. We are going to use it in combination with <a href="http://echo.labstack.com">Labstack Echo</a> (my preferred tool for creating web servers with <a href="http://golang.org">Go</a>).</p> <p>Let's define a simple webserver supporting <a href="http://jwt.io">JWT Authentication</a> like this:</p> <div class="highlight"><pre><span></span><span class="kn">package</span> <span class="nx">main</span> <span class="kn">import</span> <span class="p">(</span> <span class="s">&quot;net/http&quot;</span> <span class="s">&quot;time&quot;</span> <span class="s">&quot;github.com/dgrijalva/jwt-go&quot;</span> <span class="s">&quot;github.com/labstack/echo/v4&quot;</span> <span class="s">&quot;github.com/labstack/echo/v4/middleware&quot;</span> <span class="s">&quot;github.com/pieterclaerhout/go-log&quot;</span> <span class="p">)</span> <span class="kd">const</span> <span class="nx">secret</span> <span class="p">=</span> <span class="s">&quot;secret&quot;</span> <span class="kd">type</span> <span class="nx">jwtCustomClaims</span> <span class="kd">struct</span> <span class="p">{</span> <span class="nx">Name</span> <span class="kt">string</span> <span class="s">`json:&quot;name&quot;`</span> <span class="nx">UUID</span> <span class="kt">string</span> <span class="s">`json:&quot;uuid&quot;`</span> <span class="nx">Admin</span> <span class="kt">bool</span> <span class="s">`json:&quot;admin&quot;`</span> <span class="nx">jwt</span><span class="p">.</span><span class="nx">StandardClaims</span> <span class="p">}</span> <span class="kd">func</span> <span class="nx">login</span><span class="p">(</span><span class="nx">c</span> <span class="nx">echo</span><span class="p">.</span><span class="nx">Context</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span> <span class="nx">username</span> <span class="o">:=</span> <span class="nx">c</span><span class="p">.</span><span class="nx">FormValue</span><span class="p">(</span><span class="s">&quot;username&quot;</span><span class="p">)</span> <span class="nx">password</span> <span class="o">:=</span> <span class="nx">c</span><span class="p">.</span><span class="nx">FormValue</span><span class="p">(</span><span class="s">&quot;password&quot;</span><span class="p">)</span> <span class="k">if</span> <span class="nx">username</span> <span class="o">!=</span> <span class="s">&quot;pieter&quot;</span> <span class="o">||</span> <span class="nx">password</span> <span class="o">!=</span> <span class="s">&quot;claerhout&quot;</span> <span class="p">{</span> <span class="k">return</span> <span class="nx">echo</span><span class="p">.</span><span class="nx">ErrUnauthorized</span> <span class="p">}</span> <span class="nx">claims</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">jwtCustomClaims</span><span class="p">{</span> <span class="nx">Name</span><span class="p">:</span> <span class="s">&quot;Pieter Claerhout&quot;</span><span class="p">,</span> <span class="nx">UUID</span><span class="p">:</span> <span class="s">&quot;9E98C454-C7AC-4330-B2EF-983765E00547&quot;</span><span class="p">,</span> <span class="nx">Admin</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">StandardClaims</span><span class="p">:</span> <span class="nx">jwt</span><span class="p">.</span><span class="nx">StandardClaims</span><span class="p">{</span> <span class="nx">ExpiresAt</span><span class="p">:</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Now</span><span class="p">().</span><span class="nx">Add</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">Hour</span> <span class="o">*</span> <span class="mi">72</span><span class="p">).</span><span class="nx">Unix</span><span class="p">(),</span> <span class="p">},</span> <span class="p">}</span> <span class="nx">token</span> <span class="o">:=</span> <span class="nx">jwt</span><span class="p">.</span><span class="nx">NewWithClaims</span><span class="p">(</span><span class="nx">jwt</span><span class="p">.</span><span class="nx">SigningMethodHS256</span><span class="p">,</span> <span class="nx">claims</span><span class="p">)</span> <span class="nx">t</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">token</span><span class="p">.</span><span class="nx">SignedString</span><span class="p">([]</span><span class="nb">byte</span><span class="p">(</span><span class="nx">secret</span><span class="p">))</span> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span> <span class="k">return</span> <span class="nx">err</span> <span class="p">}</span> <span class="k">return</span> <span class="nx">c</span><span class="p">.</span><span class="nx">JSON</span><span class="p">(</span><span class="nx">http</span><span class="p">.</span><span class="nx">StatusOK</span><span class="p">,</span> <span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">string</span><span class="p">{</span> <span class="s">&quot;token&quot;</span><span class="p">:</span> <span class="nx">t</span><span class="p">,</span> <span class="p">})</span> <span class="p">}</span> <span class="kd">func</span> <span class="nx">accessible</span><span class="p">(</span><span class="nx">c</span> <span class="nx">echo</span><span class="p">.</span><span class="nx">Context</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span> <span class="k">return</span> <span class="nx">c</span><span class="p">.</span><span class="nx">String</span><span class="p">(</span><span class="nx">http</span><span class="p">.</span><span class="nx">StatusOK</span><span class="p">,</span> <span class="s">&quot;Accessible&quot;</span><span class="p">)</span> <span class="p">}</span> <span class="kd">func</span> <span class="nx">restricted</span><span class="p">(</span><span class="nx">c</span> <span class="nx">echo</span><span class="p">.</span><span class="nx">Context</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span> <span class="nx">user</span> <span class="o">:=</span> <span class="nx">c</span><span class="p">.</span><span class="nx">Get</span><span class="p">(</span><span class="s">&quot;user&quot;</span><span class="p">).(</span><span class="o">*</span><span class="nx">jwt</span><span class="p">.</span><span class="nx">Token</span><span class="p">)</span> <span class="nx">claims</span> <span class="o">:=</span> <span class="nx">user</span><span class="p">.</span><span class="nx">Claims</span><span class="p">.(</span><span class="o">*</span><span class="nx">jwtCustomClaims</span><span class="p">)</span> <span class="nx">log</span><span class="p">.</span><span class="nx">InfoDump</span><span class="p">(</span><span class="nx">claims</span><span class="p">,</span> <span class="s">&quot;claims&quot;</span><span class="p">)</span> <span class="nx">name</span> <span class="o">:=</span> <span class="nx">claims</span><span class="p">.</span><span class="nx">Name</span> <span class="k">return</span> <span class="nx">c</span><span class="p">.</span><span class="nx">String</span><span class="p">(</span><span class="nx">http</span><span class="p">.</span><span class="nx">StatusOK</span><span class="p">,</span> <span class="s">&quot;Welcome &quot;</span><span class="o">+</span><span class="nx">name</span><span class="o">+</span><span class="s">&quot;!&quot;</span><span class="p">)</span> <span class="p">}</span> <span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span> <span class="nx">e</span> <span class="o">:=</span> <span class="nx">echo</span><span class="p">.</span><span class="nx">New</span><span class="p">()</span> <span class="nx">e</span><span class="p">.</span><span class="nx">HideBanner</span> <span class="p">=</span> <span class="kc">true</span> <span class="nx">e</span><span class="p">.</span><span class="nx">HidePort</span> <span class="p">=</span> <span class="kc">true</span> <span class="nx">e</span><span class="p">.</span><span class="nx">Use</span><span class="p">(</span><span class="nx">middleware</span><span class="p">.</span><span class="nx">Logger</span><span class="p">())</span> <span class="nx">e</span><span class="p">.</span><span class="nx">Use</span><span class="p">(</span><span class="nx">middleware</span><span class="p">.</span><span class="nx">Recover</span><span class="p">())</span> <span class="nx">e</span><span class="p">.</span><span class="nx">POST</span><span class="p">(</span><span class="s">&quot;/login&quot;</span><span class="p">,</span> <span class="nx">login</span><span class="p">)</span> <span class="nx">e</span><span class="p">.</span><span class="nx">GET</span><span class="p">(</span><span class="s">&quot;/&quot;</span><span class="p">,</span> <span class="nx">accessible</span><span class="p">)</span> <span class="nx">r</span> <span class="o">:=</span> <span class="nx">e</span><span class="p">.</span><span class="nx">Group</span><span class="p">(</span><span class="s">&quot;/restricted&quot;</span><span class="p">)</span> <span class="nx">config</span> <span class="o">:=</span> <span class="nx">middleware</span><span class="p">.</span><span class="nx">JWTConfig</span><span class="p">{</span> <span class="nx">Claims</span><span class="p">:</span> <span class="o">&amp;</span><span class="nx">jwtCustomClaims</span><span class="p">{},</span> <span class="nx">SigningKey</span><span class="p">:</span> <span class="p">[]</span><span class="nb">byte</span><span class="p">(</span><span class="s">&quot;secret&quot;</span><span class="p">),</span> <span class="p">}</span> <span class="nx">r</span><span class="p">.</span><span class="nx">Use</span><span class="p">(</span><span class="nx">middleware</span><span class="p">.</span><span class="nx">JWTWithConfig</span><span class="p">(</span><span class="nx">config</span><span class="p">))</span> <span class="nx">r</span><span class="p">.</span><span class="nx">GET</span><span class="p">(</span><span class="s">&quot;&quot;</span><span class="p">,</span> <span class="nx">restricted</span><span class="p">)</span> <span class="nx">e</span><span class="p">.</span><span class="nx">Logger</span><span class="p">.</span><span class="nx">Fatal</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">Start</span><span class="p">(</span><span class="s">&quot;:8080&quot;</span><span class="p">))</span> <span class="p">}</span> </pre></div> <p>Looking at the code, there are several endpoints defined:</p> <ul> <li><code>/login</code>: can be used to get a JWT token based on your login credentials</li> <li><code>/</code>: an endpoint which doesn't require authentication</li> <li><code>/restricted</code>: an endpoint which does require a valid JWT authentication token</li> </ul> <p>The server will register itself on port <code>8080</code> and we're ready to go.</p> <p>You can start the server like:</p> <pre><code>$ go run server.go</code></pre> <p>You can then use the <code>/login</code> endpoint to get a token:</p> <pre><code>$ curl -s -X POST -d 'username=pieter' -d 'password=claerhout' http://localhost:8080/login {"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiUGlldGVyIENsYWVyaG91dCIsInV1aWQiOiI5RTk4QzQ1NC1DN0FDLTQzMzAtQjJFRi05ODM3NjVFMDA1NDciLCJhZG1pbiI6dHJ1ZSwiZXhwIjoxNjEwMzgzNTU0fQ.JqJ4x2yPXOmxJB1n4GqpfKnIMyorX2zF7kbWbfchX4c"}</code></pre> <p>You can then use this token to access the restricted URL:</p> <pre><code>$ curl http://localhost:8080/restricted -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiUGlldGVyIENsYWVyaG91dCIsInV1aWQiOiI5RTk4QzQ1NC1DN0FDLTQzMzAtQjJFRi05ODM3NjVFMDA1NDciLCJhZG1pbiI6dHJ1ZSwiZXhwIjoxNjEwMzgzNTU0fQ.JqJ4x2yPXOmxJB1n4GqpfKnIMyorX2zF7kbWbfchX4c" Welcome Pieter Claerhout!</code></pre> <p>In addition, the server log will show you the contents of the authentication token:</p> <pre><code>claims &amp;main.jwtCustomClaims{ Name: "Pieter Claerhout", UUID: "9E98C454-C7AC-4330-B2EF-983765E00547", Admin: true, StandardClaims: jwt.StandardClaims{ Audience: "", ExpiresAt: 1610383647, Id: "", IssuedAt: 0, Issuer: "", NotBefore: 0, Subject: "", }, }</code></pre> <p>The complete working implementation can be found <a href="https://github.com/pieterclaerhout/example-jwt">on GitHub</a>.</p>

Related Posts

  • Looking up a CNAME in Go
  • Gotcha with defer in Go
  • Parsing a key pair from a PEM file in Go
  • Using the Docker client from Go part 1
  • Embedding file with Go 1.16