package auth import ( "errors" "github.com/google/uuid" "gorm.io/gorm" "merch-parser-api/internal/interfaces" "merch-parser-api/internal/shared" "time" ) type Service struct { repo Repository jwtProvider interfaces.JWTProvider refreshExpiry time.Duration } func newService(repo Repository, jwtProvider interfaces.JWTProvider) *Service { return &Service{ repo: repo, jwtProvider: jwtProvider, } } func (s *Service) Login(userUuid string) (shared.AuthData, error) { return s.newSession(userUuid) } func (s *Service) Refresh(userUuid, refreshUuid string) (shared.AuthData, error) { var err error tokenData, err := s.repo.ReadRefreshToken(userUuid, refreshUuid) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return shared.AuthData{}, errors.New("refresh token is not valid or doesn't exist") } return shared.AuthData{}, err } if time.Now().After(tokenData.Expires) { _ = s.repo.InvalidateRefreshToken(userUuid, refreshUuid) return shared.AuthData{}, errors.New("token expired") } err = s.repo.InvalidateRefreshToken(userUuid, refreshUuid) if err != nil { return shared.AuthData{}, err } return s.updateSession(userUuid, tokenData.SessionUuid) } func (s *Service) Logout(userUuid, refreshUuid string) error { return s.repo.InvalidateRefreshToken(userUuid, refreshUuid) } func (s *Service) newSession(userUuid string) (shared.AuthData, error) { return s.createSession(userUuid, uuid.NewString()) } func (s *Service) updateSession(userUuid, sessionUuid string) (shared.AuthData, error) { return s.createSession(userUuid, sessionUuid) } func (s *Service) createSession(userUuid, sessionUuid string) (shared.AuthData, error) { accessToken, err := s.jwtProvider.CreateAccessToken(userUuid, sessionUuid) if err != nil { return shared.AuthData{}, err } refreshUuid := uuid.NewString() expires := time.Now().UTC().Add(s.refreshExpiry) refreshCookie := s.jwtProvider.CreateRefreshToken(refreshUuid, expires) err = s.repo.CreateRefreshToken(&Session{ Expires: expires, UserUuid: userUuid, RefreshUuid: refreshUuid, SessionUuid: sessionUuid, }) return shared.AuthData{ AccessToken: accessToken, RefreshCookie: refreshCookie, }, nil }