Search code examples
vue.jsgocorsweb-development-servergo-gin

Vue + Golang : Access to XMLHttpRequest at [Apiurl] from origin has been blocked by CORS policy: Request header field authorization is not allowed


I am beginner to Vuejs & golang. I got following error when I try to send Authorization token thorugh header while calling api from vue axios.

Access to XMLHttpRequest at 'http://localhost:5000/greet/hello' from origin 'http://localhost:5500' has been blocked by CORS policy: Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response.

[Actually I got error in my another project. but to understand solution I implement this in simple following project. So anyone can test code at their end and provide solution]

App.go

package main

import (
    "fmt"

    "github.com/gin-contrib/cors"
    "github.com/gin-gonic/gin"
)

func main() {
    router := gin.Default()
    router.Use(cors.Default())
    router.Use(Authenticate())

    v1 := router.Group("/greet")
    {
        v1.POST("/hello", handleFunc)
    }
    router.Run(":5000")
}

func handleFunc(c *gin.Context) {
    var student struct {
        Name string `json:"name"`
    }

    if c.BindJSON(&student) != nil {
        c.JSON(400, gin.H{"message": "Provide required details."})
        c.Abort()
        return
    }

    message := fmt.Sprintf("%s%s", "Good Morning ", student.Name)

    c.JSON(200, gin.H{"message": message})
}

func Authenticate() gin.HandlerFunc {

    return func(c *gin.Context) {

        requiredToken := c.Request.Header["Authorization"]

        if len(requiredToken) == 0 {
            c.JSON(400, gin.H{"message": "No token found"})
            c.Abort()
            return
        }

        fmt.Println(requiredToken)

        c.Next()
    }
}

index.html

<html>
    <head>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.js"></script>
    </head>
    <body>
        <div id="app" class="container m-5">
            <p>{{name}}</p>
            <input type="text" class="form-control col-3" placeholder="Enter Name" v-model="name"/><br>
            <button @click="onButtonClick" class="btn btn-info">CALL API</button>
        </div>
        <script src="index.js"></script>
    </body>
</html>

index.js

var app = new Vue({
  el: '#app',
  data: {
    name: ""
  },
  methods: {
    onButtonClick() {
      axios
        .post("http://localhost:5000/greet/hello",
          {
            Name: this.name
          },
          {
            headers: {
              Authorization: "HEY"
            }
          })
        .then((response) => {
          if (response.status == 200) {
            alert(response.data.message);
          }
        })
        .catch((error) => {
          console.log(error);
          alert(error.response.data.message);
        });
    },
  }
})

Solution

  • Basically you are not allowed to have Allowed-Origin: * when sending the Authorization header so you'll have to specify the domain that is allowed, you can achieve this by changing the CORS middleware instead of using the default router.Use(cors.Default())

    you could use something like this

    router.Use(cors.New(cors.Config{
        AllowOrigins:     []string{"http://localhost:5500"},
        AllowMethods:     []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"},
        AllowHeaders:     []string{"Origin", "Content-Length", "Content-Type", "Authorization"},
        ExposeHeaders:    []string{"Content-Length"},
        AllowCredentials: true,
        MaxAge: 12 * time.Hour,
    }))
    

    you can also use the AllowOriginFunc cors.Config property for a dynamic logic (in case you want to support multiple domains).

    Notice how the AllowOrigin property contains the domain of your vue project. Obviously you can allow more headers but the ones listed here are the ones you were allowing previously by using the Default config