package auth import ( "errors" "log" "time" "golang.org/x/oauth2" "github.com/gbrlsnchs/jwt/v3" ) var ( singingSecret = jwt.NewHS512([]byte("the wolf says moo")) // ErrInvalidToken error for token ErrInvalidToken = errors.New("Invalid token provided") // ErrInvalidJWT error for jwt ErrInvalidJWT = errors.New("Invalid JWT") // ErrUnauthorized error for unauthorized access ErrUnauthorized = errors.New("Unauthorized") ) // Servicer access to auth functionality type Servicer interface { LoginOrRegisterSessionID(t *oauth2.Token, gp *GoogleAuthProfile) (string, bool, error) GenerateStateToken() (string, error) ValidateStateToken(token string, sessionToken string) (bool, error) } // Service a container for auth deps type Service struct { repo Repo } // NewService create auth service func NewService(repo Repo) *Service { return &Service{ repo, } } // GenerateStateToken create a random token for oauth exchange func (a *Service) GenerateStateToken() (string, error) { now := time.Now() pl := jwt.Payload{ Issuer: "iserv-state", Subject: "state param", IssuedAt: jwt.NumericDate(now), } tokenBytes, err := jwt.Sign(pl, singingSecret) if err != nil { return "", err } return string(tokenBytes[:]), err } // ValidateStateToken validate provided token func (a *Service) ValidateStateToken(token string, sessionToken string) (bool, error) { if token == sessionToken { p := jwt.Payload{} _, err := jwt.Verify([]byte(token), singingSecret, &p) if err != nil { return false, ErrInvalidJWT } return true, nil } return false, ErrInvalidToken } // LoginOrRegisterSessionID create a login func (a *Service) LoginOrRegisterSessionID(t *oauth2.Token, gp *GoogleAuthProfile) (string, bool, error) { isAuthorized, err := a.repo.IsAuthorized(gp) newRegistration := false if err != nil { return "", newRegistration, err } if isAuthorized != true { return "", newRegistration, ErrUnauthorized } profileID, err := a.repo.LookUpAuthProfileID(gp) if err != nil { return "", newRegistration, err } if profileID == "" { // create profile log.Printf("creating new profile") profile := NewAuthProfile(t, gp) profileID = profile.ID log.Printf("new profile %+v", profile) err = a.repo.SaveAuthProfile(profile) if err != nil { return "", newRegistration, err } newRegistration = true } return profileID, newRegistration, nil }