onasty/internal/service/usersrv/oauth.go(view raw)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
package usersrv
import (
"context"
"errors"
"log/slog"
"strings"
"time"
"github.com/gofrs/uuid/v5"
"github.com/olexsmir/onasty/internal/dtos"
"github.com/olexsmir/onasty/internal/models"
"github.com/olexsmir/onasty/internal/oauth"
)
var ErrProviderNotSupported = errors.New("oauth2 provider not supported")
const (
googleProvider = "google"
githubProvider = "github"
)
func (u *UserSrv) GetOAuthURL(providerName string) (string, error) {
switch providerName {
case googleProvider:
return u.googleOauth.GetAuthURL(""), nil
case githubProvider:
return u.githubOauth.GetAuthURL(""), nil
default:
return "", ErrProviderNotSupported
}
}
func (u *UserSrv) HandleOAuthLogin(
ctx context.Context,
providerName, code string,
) (dtos.Tokens, error) {
userInfo, err := u.getUserInfoBasedOnProvider(ctx, providerName, code)
if err != nil {
return dtos.Tokens{}, err
}
userID, err := u.getUserByOAuthIDOrCreateOne(ctx, userInfo)
if err != nil {
return dtos.Tokens{}, err
}
if err = u.userstore.LinkOAuthIdentity(ctx, userID, userInfo.Provider, userInfo.ProviderID); err != nil {
slog.ErrorContext(ctx, "failed to link user identity", "user_id", userID, "err", err)
return dtos.Tokens{}, err
}
tokens, err := u.issueTokens(ctx, userID)
return tokens, err
}
func (u *UserSrv) getUserInfoBasedOnProvider(
ctx context.Context,
providerName, code string,
) (oauth.UserInfo, error) {
var userInfo oauth.UserInfo
var err error
switch providerName {
case googleProvider:
userInfo, err = u.googleOauth.ExchangeCode(ctx, code)
case githubProvider:
userInfo, err = u.githubOauth.ExchangeCode(ctx, code)
default:
return oauth.UserInfo{}, ErrProviderNotSupported
}
return userInfo, err
}
func getUsernameFromEmail(email string) string {
p := strings.Split(email, "@")
return p[0]
}
func (u *UserSrv) getUserByOAuthIDOrCreateOne(
ctx context.Context,
info oauth.UserInfo,
) (uuid.UUID, error) {
user, err := u.userstore.GetByOAuthID(ctx, info.Provider, info.ProviderID)
if err != nil {
if errors.Is(err, models.ErrUserNotFound) {
uid, cerr := u.userstore.Create(ctx, models.User{
ID: uuid.Nil,
Username: getUsernameFromEmail(info.Email),
Email: info.Email,
Activated: true,
Password: "",
CreatedAt: time.Now(),
LastLoginAt: time.Now(),
})
return uid, cerr
}
return uuid.Nil, err
}
return user.ID, nil
}
|