feat: auth handlers

This commit is contained in:
2025-09-07 16:45:20 +03:30
parent 5c5df48644
commit f4e5e074d3
11 changed files with 227 additions and 4 deletions
View File
+27
View File
@@ -0,0 +1,27 @@
package dto
type ChallengeRequest struct {
PubKey string `json:"pubKey" validate:"required,eth_pubkey"`
}
type ChallengeResponse struct {
Message string `json:"message"`
TimeStamp string `json:"timeStamp"`
ExpiresAt string `json:"expiresAt"`
}
type AuthenticateRequest struct {
PubKey string `json:"pubKey" validate:"required,eth_pubkey"`
Signature string `json:"signature" validate:"required,eth_signature"`
Message string `json:"message" validate:"required,uuid"`
}
type AuthenticateResponse struct {
AuthorizationToken string `json:"authorizationToken"`
RefreshToken string `json:"refreshToken"`
ExpiresAt int64 `json:"expiresAt"`
}
type RefreshTokenRequest struct {
RefreshToken string `json:"refreshToken" validate:"required,jwt"`
}
View File
@@ -0,0 +1,90 @@
package http
import (
"backend/internal/api/dto"
"backend/internal/domain"
"backend/internal/usecase"
"time"
"github.com/gofiber/fiber/v2"
"github.com/google/uuid"
)
type AuthHandler struct {
authService usecase.AuthService
}
func NewAuthHandler(authService *usecase.AuthService) *AuthHandler {
return &AuthHandler{
authService: *authService,
}
}
func (h *AuthHandler) GenerateChallenge(c *fiber.Ctx) error {
var req dto.ChallengeRequest
if err := c.BodyParser(&req); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": "invalid request body",
})
}
challenge, err := h.authService.GenerateChallenge(c.Context(), req.PubKey)
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": "failed to generate challenge",
})
}
return c.Status(fiber.StatusOK).JSON(
dto.ChallengeResponse{
Message: challenge.Message.String(),
TimeStamp: challenge.TimeStamp.String(),
ExpiresAt: challenge.ExpiresAt.String(),
},
)
}
func (h *AuthHandler) Authenticate(c *fiber.Ctx) error {
var req dto.AuthenticateRequest
if err := c.BodyParser(&req); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": "invalid request body",
})
}
messageUUID, err := uuid.Parse(req.Message)
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": "invalid message format",
})
}
challenge := &domain.Challenge{
Message: messageUUID,
TimeStamp: time.Now().UTC(),
ExpiresAt: time.Now().Add(5 * time.Minute),
}
clientIP := c.IP()
userAgent := c.Get("User-Agent")
userToken, err := h.authService.Authenticate(
c.Context(),
req.PubKey,
req.Signature,
challenge,
// add chainID to cfg
1,
clientIP,
userAgent,
)
if err != nil {
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
"error": err.Error(),
})
}
return c.Status(fiber.StatusOK).JSON(dto.AuthenticateResponse{
AuthorizationToken: userToken.AuthorizationToken,
RefreshToken: userToken.RefreshToken,
ExpiresAt: userToken.ExpiresAt,
})
}
+37
View File
@@ -0,0 +1,37 @@
package middlewares
import (
"backend/pkg/jwt"
"strings"
"github.com/gofiber/fiber/v2"
)
const userClaimsKey = "User-Claims"
func JWTAuthMiddleware(secret []byte) fiber.Handler {
return func(c *fiber.Ctx) error {
authHeader := c.Get("Authorization")
if authHeader == "" || !strings.HasPrefix(authHeader, "Bearer ") {
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
"error": "missing or invalid Authorization header",
})
}
tokenString := strings.TrimPrefix(authHeader, "Bearer ")
claims, err := jwt.ParseToken(tokenString, secret)
if err != nil || claims == nil {
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
"error": "invalid or expired token",
})
}
c.Locals(userClaimsKey, claims)
return c.Next()
}
}
func GetUserClaims(c *fiber.Ctx) *jwt.UserClaims {
claims, _ := c.Locals(userClaimsKey).(*jwt.UserClaims)
return claims
}
+27
View File
@@ -0,0 +1,27 @@
package http
import (
"backend/config"
"backend/internal/app"
"fmt"
"log"
"github.com/gofiber/fiber/v2"
)
func Run(cfg config.Server, app *app.AppContainer) {
fiberApp := fiber.New()
api := fiberApp.Group("/api")
// register routes here
registerPublicRoutes(api, app)
log.Fatal(fiberApp.Listen(fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)))
}
func registerPublicRoutes(router fiber.Router, app *app.AppContainer) {
authgroup := router.Group("/auth")
//TODO: implement handlers
authgroup.Post("/challenge")
authgroup.Post("/authenticate")
}
View File