Go JWT Authentication with keycloak

Recently I was working on a React project with Go backend using Gin web framework. Keycloak was the authentication mechanism for the frontend; I also wanted to secure the backend using JSON Web Tokens which was provided by Keycloak on every login. Setup for jwt verification in Go was easy.

First, copy RS256 algorithm public key value from Keycloak

Send the token as Authorization header

axios
  .get(BACKEND_URL.concat("sampleendpoint"), {
    headers: {
      Authorization: this.state.token
    }
  })
  .then(res => {});

Now Go-backend setup; let’s install the jwt-go, gin-cors libraries:

$ go get -u github.com/dgrijalva/jwt-go
$ go get -u github.com/gin-contrib/cors

Add cors config to the router to allow authorization header

router.Use(cors.New(cors.Config{
  AllowOrigins:     []string{"*"},
  AllowMethods:     []string{"GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD"},
  AllowHeaders:     []string{"Origin", "ontent-type", "accept", "authorization"},
  ExposeHeaders:    []string{"Content-Length"},
  AllowCredentials: true,
  MaxAge:           12 * time.Hour,
}))

Let’s create a custom handler; add the public key from Keycloak and pass it to ParseRSAPublicKeyFromPEM which will return a key. The key and token are then validated

func VerifyToken(c *gin.Context) {
  SecretKey := "-----BEGIN CERTIFICATE-----\n"+
  "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApn
  ......
  +wnyuCHaCHp8P1yCnwIDAQAB" + "\n-----END CERTIFICATE-----"

	reqToken := c.GetHeader("Authorization")

	key, er := jwt.ParseRSAPublicKeyFromPEM([]byte(SecretKey))
	if er != nil {
		fmt.Println(er)
		c.Abort()
		c.Writer.WriteHeader(http.StatusUnauthorized)
		c.Writer.Write([]byte("Unauthorized"))
		return
	}

	token, err := jwt.Parse(reqToken, func(token *jwt.Token) (interface{}, error) {
		// Don't forget to validate the alg is what you expect:
		if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
			return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
		}
		return key, nil
	})

	if err != nil {
		fmt.Println(err)
		c.Abort()
		c.Writer.WriteHeader(http.StatusUnauthorized)
		c.Writer.Write([]byte("Unauthorized"))
		return
	}

	if _, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		fmt.Println("token is valid")
	}
}

Add the handler to the route

router.GET("/sample", VerifyToken(), handlers.SampleEndpoint)

That’s, it done, If the token is valid, you will get the data from backend or else you’ll see 401 Unauthorized

Built with Hugo
Theme Stack designed by Jimmy