Files
drive/apps/backend/internal/auth/service.go

129 lines
2.6 KiB
Go
Raw Normal View History

package auth
import (
"context"
"encoding/hex"
"errors"
"github.com/get-drexa/drexa/internal/password"
2025-11-26 01:09:42 +00:00
"github.com/get-drexa/drexa/internal/user"
"github.com/google/uuid"
"github.com/uptrace/bun"
)
type LoginResult struct {
2025-11-26 01:09:42 +00:00
User *user.User
AccessToken string
RefreshToken string
}
var ErrInvalidCredentials = errors.New("invalid credentials")
type Service struct {
db *bun.DB
2025-11-26 01:09:42 +00:00
userService *user.Service
tokenConfig TokenConfig
}
type registerOptions struct {
displayName string
email string
password string
}
2025-11-26 01:09:42 +00:00
func NewService(db *bun.DB, userService *user.Service, tokenConfig TokenConfig) *Service {
return &Service{
db: db,
2025-11-26 01:09:42 +00:00
userService: userService,
tokenConfig: tokenConfig,
}
}
func (s *Service) LoginWithEmailAndPassword(ctx context.Context, email, plain string) (*LoginResult, error) {
u, err := s.userService.UserByEmail(ctx, email)
if err != nil {
var nf *user.NotFoundError
if errors.As(err, &nf) {
return nil, ErrInvalidCredentials
}
return nil, err
}
ok, err := password.Verify(plain, u.Password)
if err != nil || !ok {
return nil, ErrInvalidCredentials
}
at, err := GenerateAccessToken(u, &s.tokenConfig)
if err != nil {
return nil, err
}
rt, err := GenerateRefreshToken(u, &s.tokenConfig)
if err != nil {
return nil, err
}
_, err = s.db.NewInsert().Model(rt).Exec(ctx)
if err != nil {
return nil, err
}
return &LoginResult{
User: u,
AccessToken: at,
RefreshToken: hex.EncodeToString(rt.Token),
}, nil
}
func (s *Service) Register(ctx context.Context, opts registerOptions) (*LoginResult, error) {
hashed, err := password.Hash(opts.password)
if err != nil {
return nil, err
}
u, err := s.userService.RegisterUser(ctx, user.UserRegistrationOptions{
Email: opts.email,
DisplayName: opts.displayName,
Password: hashed,
})
if err != nil {
return nil, err
}
at, err := GenerateAccessToken(u, &s.tokenConfig)
if err != nil {
return nil, err
}
rt, err := GenerateRefreshToken(u, &s.tokenConfig)
if err != nil {
return nil, err
}
_, err = s.db.NewInsert().Model(rt).Exec(ctx)
if err != nil {
return nil, err
}
return &LoginResult{
User: u,
AccessToken: at,
RefreshToken: hex.EncodeToString(rt.Token),
}, nil
}
2025-11-26 01:09:42 +00:00
func (s *Service) AuthenticateWithAccessToken(ctx context.Context, token string) (*user.User, error) {
claims, err := ParseAccessToken(token, &s.tokenConfig)
if err != nil {
return nil, err
}
id, err := uuid.Parse(claims.Subject)
if err != nil {
return nil, newInvalidAccessTokenError(err)
}
return s.userService.UserByID(ctx, id)
}