2 Commits

Author SHA1 Message Date
Fran Jurmanović
edad65d6a9 generate open token using normal token
All checks were successful
Release and Deploy / build (push) Successful in 3m1s
Release and Deploy / deploy (push) Successful in 23s
2025-08-17 12:46:37 +02:00
Fran Jurmanović
486c972bba open token authentication
All checks were successful
Release and Deploy / build (push) Successful in 3m51s
Release and Deploy / deploy (push) Successful in 28s
2025-08-17 12:15:39 +02:00
7 changed files with 34 additions and 19 deletions

View File

@@ -34,7 +34,7 @@ func NewMembershipController(service *service.MembershipService, auth *middlewar
}
routeGroups.Auth.Post("/login", mc.Login)
routeGroups.Auth.Post("/open-token", mc.GenerateOpenToken)
routeGroups.Auth.Post("/open-token", mc.auth.Authenticate, mc.GenerateOpenToken)
usersGroup := routeGroups.Membership
usersGroup.Use(mc.auth.Authenticate)

View File

@@ -52,20 +52,28 @@ func NewAuthMiddleware(ms *service.MembershipService, cache *cache.InMemoryCache
// Authenticate is a middleware for JWT authentication with enhanced security.
func (m *AuthMiddleware) AuthenticateOpen(ctx *fiber.Ctx) error {
return m.AuthenticateWithHandler(m.openJWTHandler.JWTHandler, ctx)
return m.AuthenticateWithHandler(m.openJWTHandler.JWTHandler, true, ctx)
}
// Authenticate is a middleware for JWT authentication with enhanced security.
func (m *AuthMiddleware) Authenticate(ctx *fiber.Ctx) error {
return m.AuthenticateWithHandler(m.jwtHandler, ctx)
return m.AuthenticateWithHandler(m.jwtHandler, false, ctx)
}
func (m *AuthMiddleware) AuthenticateWithHandler(jwtHandler *jwt.JWTHandler, ctx *fiber.Ctx) error {
func (m *AuthMiddleware) AuthenticateWithHandler(jwtHandler *jwt.JWTHandler, isOpenToken bool, ctx *fiber.Ctx) error {
// Log authentication attempt
ip := ctx.IP()
userAgent := ctx.Get("User-Agent")
authHeader := ctx.Get("Authorization")
if jwtHandler.IsOpenToken && !isOpenToken {
logging.Error("Authentication failed: attempting to authenticate with open token")
return ctx.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
"error": "Wrong token type used",
})
}
if authHeader == "" {
logging.Error("Authentication failed: missing Authorization header from IP %s", ip)
return ctx.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
@@ -98,6 +106,13 @@ func (m *AuthMiddleware) AuthenticateWithHandler(jwtHandler *jwt.JWTHandler, ctx
})
}
if !jwtHandler.IsOpenToken && claims.IsOpenToken {
logging.Error("Authentication failed: attempting to authenticate with open token")
return ctx.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
"error": "Wrong token type used",
})
}
// Additional security: validate user ID format
if claims.UserID == "" || len(claims.UserID) < 10 {
logging.Error("Authentication failed: invalid user ID in token from IP %s", ip)

View File

@@ -63,16 +63,11 @@ func (s *MembershipService) Login(ctx context.Context, username, password string
return "", err
}
return s.jwtHandler.GenerateToken(user)
return s.jwtHandler.GenerateToken(user.ID.String())
}
func (s *MembershipService) GenerateOpenToken(ctx context.Context, userId string) (string, error) {
user, err := s.repo.GetByID(ctx, userId)
if err != nil {
return "", err
}
return s.openJwtHandler.GenerateToken(user)
return s.openJwtHandler.GenerateToken(userId)
}
// CreateUser creates a new user.

View File

@@ -8,7 +8,7 @@ import (
)
var (
Version = "0.10.5"
Version = "0.10.6"
Prefix = "v1"
Secret string
SecretCode string

View File

@@ -13,12 +13,14 @@ import (
// Claims represents the JWT claims.
type Claims struct {
UserID string `json:"user_id"`
UserID string `json:"user_id"`
IsOpenToken bool `json:"is_open_token"`
jwt.RegisteredClaims
}
type JWTHandler struct {
SecretKey []byte
SecretKey []byte
IsOpenToken bool
}
type OpenJWTHandler struct {
@@ -28,6 +30,7 @@ type OpenJWTHandler struct {
// NewJWTHandler creates a new JWTHandler instance with the provided secret key.
func NewOpenJWTHandler(jwtSecret string) *OpenJWTHandler {
jwtHandler := NewJWTHandler(jwtSecret)
jwtHandler.IsOpenToken = true
return &OpenJWTHandler{
JWTHandler: jwtHandler,
}
@@ -68,13 +71,14 @@ func (jh *JWTHandler) GenerateSecretKey() string {
}
// GenerateToken generates a new JWT for a given user.
func (jh *JWTHandler) GenerateToken(user *model.User) (string, error) {
func (jh *JWTHandler) GenerateToken(userId string) (string, error) {
expirationTime := time.Now().Add(24 * time.Hour)
claims := &Claims{
UserID: user.ID.String(),
UserID: userId,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(expirationTime),
},
IsOpenToken: jh.IsOpenToken,
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
@@ -88,6 +92,7 @@ func (jh *JWTHandler) GenerateTokenWithExpiry(user *model.User, expiry time.Time
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(expirationTime),
},
IsOpenToken: jh.IsOpenToken,
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

View File

@@ -28,7 +28,7 @@ func GenerateTestToken() (string, error) {
jwtHandler := jwt.NewJWTHandler(testSecret)
// Generate JWT token
token, err := jwtHandler.GenerateToken(user)
token, err := jwtHandler.GenerateToken(user.ID.String())
if err != nil {
return "", fmt.Errorf("failed to generate test token: %w", err)
}

View File

@@ -26,7 +26,7 @@ func TestJWT_GenerateAndValidateToken(t *testing.T) {
}
// Test JWT generation
token, err := jwtHandler.GenerateToken(user)
token, err := jwtHandler.GenerateToken(user.ID.String())
tests.AssertNoError(t, err)
tests.AssertNotNil(t, token)