How to validate API key in go-gin framework?

Viewed 1504

So I currently have a function that will take in a string APIKey to check it against my MongoDB collection. If nothing is found (not authenticated), it returns false - if a user is found, it returns true. My problem, however, is I'm unsure how to integrate this with a Gin POST route. Here is my code:


import (
    "context"
    "fmt"
    "log"
    "os"

    "github.com/gin-gonic/gin"
    _ "github.com/joho/godotenv/autoload"
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/bson/primitive"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
)

type User struct {
    Name   string
    APIKey string
}

func validateAPIKey(users *mongo.Collection, APIKey string) bool {
    var user User

    filter := bson.D{primitive.E{Key: "APIKey", Value: APIKey}}
    if err := users.FindOne(context.TODO(), filter).Decode(&user); err != nil {
        fmt.Printf("Found 0 results for API Key: %s\n", APIKey)
        return false
    }

    fmt.Printf("Found: %s\n", user.Name)
    return true
}

func handleUpload(c *gin.Context) {

}

func main() {
    r := gin.Default()

    api := r.Group("/api")
    v1 := api.Group("/v1")

    v1.POST("/upload", handleUpload)

    mongoURI := os.Getenv("MONGO_URI")
    mongoOptions := options.Client().ApplyURI(mongoURI)
    client, err := mongo.Connect(context.TODO(), mongoOptions)
    if err != nil {
        log.Fatal(err, "Unable to access MongoDB server, exiting...")
    }
    defer client.Disconnect(context.TODO())

    // users := client.Database("sharex_api").Collection("authorized_users") // commented out when testing to ignore unused warnings

    r.Run(":8085")
}

The validateAPIKey function works exactly as intended if tested alone, I am just unsure how I would run this function for a specific endpoint (in this case, /api/v1/upload) and pass in the users collection.

1 Answers

After a bit of searching, I found a resolution. I changed my validateAPIKey function to return git.HandlerFunc. Here's the code:

func validateAPIKey(users *mongo.Collection) gin.HandlerFunc {
    return func(c *gin.Context) {
        var user authorizedUser
        APIKey := c.Request.Header.Get("X-API-Key")

        filter := bson.D{primitive.E{Key: "APIKey", Value: APIKey}}
        if err := users.FindOne(context.TODO(), filter).Decode(&user); err != nil {
            fmt.Printf("Found 0 results for API Key: %s\n", APIKey)
            c.JSON(http.StatusUnauthorized, gin.H{"status": 401, "message": "Authentication failed"})
            return
        }

        return
    }
}

For the route, I have the following:

v1.POST("/upload", validateAPIKey(users), handleUpload)
Related