added auth service to go backend

This commit is contained in:
2025-01-03 20:45:39 +00:00
parent 98fb6942fe
commit d0d88de15c
10 changed files with 297 additions and 9 deletions
@@ -0,0 +1,122 @@
package repository
import (
"actatempus_backend/internal/domain/app_error"
"actatempus_backend/internal/domain/repository"
"context"
"errors"
"fmt"
"sync"
"time"
E "github.com/IBM/fp-go/either"
"github.com/golang-jwt/jwt/v5"
)
type InMemoryAuthRepository struct {
secretKey string
sessionCache map[string]string
mu sync.RWMutex
}
func NewInMemoryAuthRepository(secretKey string) repository.AuthRepository {
return &InMemoryAuthRepository{
secretKey: secretKey,
sessionCache: make(map[string]string),
mu: sync.RWMutex{},
}
}
func (r *InMemoryAuthRepository) GenerateToken(ctx context.Context) func(userID string) E.Either[error, string] {
return func(userID string) E.Either[error, string] {
token, err := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"userID": userID,
"exp": time.Now().Add(24 * time.Hour).Unix(),
}).SignedString([]byte(r.secretKey))
// add token to cache
r.mu.Lock()
defer r.mu.Unlock() // unlock after function returns
r.sessionCache[token] = userID
return E.TryCatch(
token,
err,
func(e error) error {
return app_error.NewInternalError(fmt.Errorf("could not generate token: %w", e))
},
)
}
}
func (r *InMemoryAuthRepository) ValidateToken(ctx context.Context) func(token string) E.Either[error, string] {
return func(token string) E.Either[error, string] {
// Separate value and error generation for TryCatch
userID, err := func() (string, error) {
parsedToken, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, errors.New("invalid signing method")
}
return []byte(r.secretKey), nil
})
if err != nil {
return "", err
}
if claims, ok := parsedToken.Claims.(jwt.MapClaims); ok && parsedToken.Valid {
userID, ok := claims["userID"].(string)
if !ok {
return "", app_error.NewAuthError(fmt.Sprintf("invalid token claims"))
}
// Check the cache
r.mu.RLock()
defer r.mu.RUnlock()
if cachedUserID, exists := r.sessionCache[token]; exists && cachedUserID == userID {
return userID, nil
}
// print chache to see if it is working
fmt.Println(r.sessionCache)
return "", app_error.NewAuthError(fmt.Sprintf("token not found in cache"))
}
return "", app_error.NewAuthError(fmt.Sprintf("invalid token"))
}()
// Use TryCatch with separated value and error
return E.TryCatch(
userID,
err,
func(e error) error {
return e
},
)
}
}
func (r *InMemoryAuthRepository) RevokeToken(ctx context.Context) func(token string) E.Either[error, string] {
return func(token string) E.Either[error, string] {
// Separate value and error generation for TryCatch
userID, err := func() (string, error) {
r.mu.Lock()
defer r.mu.Unlock()
if userID, exists := r.sessionCache[token]; exists {
delete(r.sessionCache, token)
return userID, nil
}
return "", app_error.NewAuthError(fmt.Sprintf("token not found"))
}()
// Use TryCatch with separated value and error
return E.TryCatch(
userID,
err,
func(e error) error {
return e
},
)
}
}