RSVP here for our first hackathon! Free prizes, the kickoff is 8 AM PST Jan 17th

JWT Authentication in Golang

A learning path to your next coding job

  1. Join the Qvault community and share your career goals
  2. We'll help you find the knowledge gaps holding you back
  3. Complete recommended courses and projects
  4. Find your next opportunity with a newly polished resume

Our courses include but are not limited to

  • Golang, Python, JavaScript
  • Algorithms, data structures, cryptography
  • Graphics and functional programming

Go is becoming very popular for backend web development, and JWT’s are one of the most popular ways to handle authentication on API requests. In this article, we’ll go over the basics of JWT’s and how to implement a secure authentication strategy in Go!

What is a JWT?

JSON Web Tokens are an open, industry-standard RFC 7519 method for representing claims securely between two parties.

More simply put, JWT’s are encoded JSON objects that have been signed by the server, verifying authenticity.

For example, when a user logs in to a website secured via JWTs, the flow should look something like this:

  1. The user sends a username and password to the server
  2. The server verifies username and password are correct
  3. The server creates a JSON object (also known as the “claims”) that looks something like this:
    1. {"username":"wagslane"}
  4. The server encodes and signs the JSON object, creating a JWT:
    1. eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IndhZ3NsYW5lIn0.ov6d8XtwQoKUwsYahk9UwH333NICElFSs6ag6pINyPQ
  5. The user’s web client saves the JWT for later use
  6. When the user makes a request to a protected endpoint, it passes the JWT along in an HTTP header
  7. The server checks the signature on the JWT to make sure the JWT was originally created by the same server
  8. The server reads the claims and gives permission to the request to operate as “wagslane”

Create a JWT

We’re going to use a popular library for dealing with JSON Web Tokens in Go, jwt-go. Make sure you have the code cloned locally:

go get
Code language: Bash (bash)

For simplicity, we’re going to use a symmetric encryption scheme. If you go this route, it just means that any server that can verify that a JWT is valid will also be allowed to issue new JWTs.

First, define a struct that will be used to represent claims to identify your users:

type customClaims struct { Username string `json:"username"` jwt.StandardClaims }
Code language: Go (go)

The jwt.StandardClaims struct contains useful fields like expiry and issuer name. Now we’ll create some actual claims for the user that just logged in:

claims := customClaims{ Username: username, StandardClaims: jwt.StandardClaims{ ExpiresAt: 15000, Issuer: "nameOfWebsiteHere", }, }
Code language: Go (go)

Next let’s create an unsigned token from the claims:

token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
Code language: Go (go)

Then we sign the token using a secure private key. In production make sure you use a real private key, preferably at least 256 bits in length:

signedToken, err := token.SignedString([]byte("secureSecretText"))
Code language: Go (go)

Finally, the signed token can be sent back to the client.

Validating a JWT

When the client makes a request to a protected endpoint we can verify the JWT is authentic using the following steps.

*Note: It’s idiomatic to use the Authorization HTTP header:

Authorization: Bearer {jwt}
Code language: HTTP (http)

After receiving the JWT, validate the claims and verify the signature using the same private key:

token, err := jwt.ParseWithClaims( jwtFromHeader, &customClaims{}, func(token *jwt.Token) (interface{}, error) { return []byte("secureSecretText"), nil }, )
Code language: Go (go)

If the claims have been tampered with then the err variable will not be nil.

Parse the claims from the token:

claims, ok := token.Claims.(*customClaims) if !ok { return errors.New("couldn't parse claims") }
Code language: Go (go)

Check if the token is expired:

if claims.ExpiresAt < time.Now().UTC().Unix() { return errors.New("jwt is expired") }
Code language: Go (go)

You now know the username of the authenticated user!

username := claims.Username
Code language: Go (go)

For full examples take a look at the package’s tests. Let me know if I missed anything by hitting me up on Twitter!

Related Reading

Trying to find your next programming job?

If you are a self-taught developer having trouble finding your first programming job, we've got your back! We have the learning resources and tight-knit dev community that you need to land the coding job you've been looking for. To get started, create a free account and join our Discord community.

Have questions or feedback?

If we've made a mistake in the article, please let us know so we can get it corrected!