package auth import ( "context" "fmt" "github.com/food-ai/backend/internal/user" ) type Service struct { tokenVerifier TokenVerifier userRepo user.UserRepository jwtManager *JWTManager } func NewService(tokenVerifier TokenVerifier, userRepo user.UserRepository, jwtManager *JWTManager) *Service { return &Service{ tokenVerifier: tokenVerifier, userRepo: userRepo, jwtManager: jwtManager, } } type LoginResponse struct { AccessToken string `json:"access_token"` RefreshToken string `json:"refresh_token"` ExpiresIn int `json:"expires_in"` User *user.User `json:"user"` } type RefreshResponse struct { AccessToken string `json:"access_token"` RefreshToken string `json:"refresh_token"` ExpiresIn int `json:"expires_in"` } func (s *Service) Login(ctx context.Context, firebaseToken string) (*LoginResponse, error) { uid, email, name, avatarURL, err := s.tokenVerifier.VerifyToken(ctx, firebaseToken) if err != nil { return nil, fmt.Errorf("verify firebase token: %w", err) } u, err := s.userRepo.UpsertByFirebaseUID(ctx, uid, email, name, avatarURL) if err != nil { return nil, fmt.Errorf("upsert user: %w", err) } accessToken, err := s.jwtManager.GenerateAccessToken(u.ID, u.Plan) if err != nil { return nil, fmt.Errorf("generate access token: %w", err) } refreshToken, expiresAt := s.jwtManager.GenerateRefreshToken() if err := s.userRepo.SetRefreshToken(ctx, u.ID, refreshToken, expiresAt); err != nil { return nil, fmt.Errorf("set refresh token: %w", err) } return &LoginResponse{ AccessToken: accessToken, RefreshToken: refreshToken, ExpiresIn: int(s.jwtManager.AccessDuration().Seconds()), User: u, }, nil } func (s *Service) Refresh(ctx context.Context, refreshToken string) (*RefreshResponse, error) { u, err := s.userRepo.FindByRefreshToken(ctx, refreshToken) if err != nil { return nil, fmt.Errorf("invalid refresh token: %w", err) } accessToken, err := s.jwtManager.GenerateAccessToken(u.ID, u.Plan) if err != nil { return nil, fmt.Errorf("generate access token: %w", err) } newRefreshToken, expiresAt := s.jwtManager.GenerateRefreshToken() if err := s.userRepo.SetRefreshToken(ctx, u.ID, newRefreshToken, expiresAt); err != nil { return nil, fmt.Errorf("set refresh token: %w", err) } return &RefreshResponse{ AccessToken: accessToken, RefreshToken: newRefreshToken, ExpiresIn: int(s.jwtManager.AccessDuration().Seconds()), }, nil } func (s *Service) Logout(ctx context.Context, userID string) error { return s.userRepo.ClearRefreshToken(ctx, userID) }