diff --git a/api/handlers/login.go b/api/handlers/login.go index 98ca1c8..deb9fff 100644 --- a/api/handlers/login.go +++ b/api/handlers/login.go @@ -1,34 +1,56 @@ package handlers import ( + "context" "net/http" + "time" "bkawk/go-echo/api/models" + "bkawk/go-echo/api/utils" "github.com/labstack/echo/v4" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "golang.org/x/crypto/bcrypt" ) // RegisterEndpoint handles user registration requests func LoginPost(c echo.Context) error { - // bind the incoming request body to a User struct + // Get database connection from context + db := c.Get("db").(*mongo.Database) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + // Validate input u := new(models.User) if err := c.Bind(u); err != nil { return err } - // validate user input - if u.Username == "" || u.Password == "" || u.Email == "" { - return c.JSON(http.StatusBadRequest, map[string]string{ - "error": "invalid request body", - }) + // Find user by email or username + var user models.User + collection := db.Collection("users") + err := collection.FindOne(ctx, bson.M{ + "$or": []bson.M{ + {"email": u.Email}, + {"username": u.Email}, + }, + }).Decode(&user) + if err != nil { + return c.JSON(http.StatusUnauthorized, echo.Map{"error": "Invalid credentials"}) + } + + // Check if password matches + err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(u.Password)) + if err != nil { + return c.JSON(http.StatusUnauthorized, echo.Map{"error": "Invalid credentials"}) } - // add the new user to the database - // (this is a dummy implementation and would be replaced in a real application) - // ... + // Generate JWT token + token, err := utils.GenerateJWT(user.Username, user.Email) + if err != nil { + return c.JSON(http.StatusInternalServerError, echo.Map{"error": "Failed to generate token"}) + } - // return a success response - return c.JSON(http.StatusOK, map[string]string{ - "message": "user registered successfully", - }) + return c.JSON(http.StatusOK, echo.Map{"token": token}) } diff --git a/api/utils/generateJwt.go b/api/utils/generateJwt.go new file mode 100644 index 0000000..d971a3e --- /dev/null +++ b/api/utils/generateJwt.go @@ -0,0 +1,26 @@ +package utils + +import ( + "os" + "time" + + jwt "github.com/dgrijalva/jwt-go" +) + +func GenerateJWT(username, email string) (string, error) { + // Create a new JWT token + token := jwt.New(jwt.SigningMethodHS256) + + // Set claims + claims := token.Claims.(jwt.MapClaims) + claims["username"] = username + claims["email"] = email + claims["exp"] = time.Now().Add(time.Hour * 72).Unix() + + // Generate encoded token and send it as response. + t, err := token.SignedString([]byte(os.Getenv("JWT_SECRET"))) + if err != nil { + return "", err + } + return t, nil +} diff --git a/go.mod b/go.mod index 896eb15..bd916b3 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ require ( ) require ( + github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/golang/snappy v0.0.1 // indirect github.com/klauspost/compress v1.13.6 // indirect diff --git a/go.sum b/go.sum index 53e19ad..79be147 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=