README

M9 / LOGIN

A module with features to sign in and sign up using default method using API and service provider, such as Facebook & Google.

GET STARTED

  1. Copy the config.yaml.example to config.yaml
  2. Update the configuration according to your requirement.
  3. Create database (manually) and migrate the schema using this command
m9 migrate -m login --verbose
  1. Start the application server
m9 server start login

* use --verbose to verbose the sql query

FEATURES

Features Status
Feature to login/register using Facebook DONE
Feature to login/register using Google DONE
Feature to redirect to target URL feature (if enabled) after access token is genereted when login using service provider DONE
Feature to signup using normal method via REST API DONE
Feature to login using normal method via REST DONE
Feature to validate access token DONE
Feature to reset password BACKLOG
Expand ▾ Collapse ▴

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	PrometheusDefaultTotal                = instrument.NewPrometheus().NewCounter(prometheusModuleName, "default_total", "The total number of login using Default.")
	PrometheusDefaultSuccessTotal         = instrument.NewPrometheus().NewCounter(prometheusModuleName, "default_success_total", "The total number of success login using Default.")
	PrometheusDefaultFailedTotal          = instrument.NewPrometheus().NewCounter(prometheusModuleName, "default_failed_total", "The total number of failed login using Default.")
	PrometheusRegisterDefaultTotal        = instrument.NewPrometheus().NewCounter(prometheusModuleName, "default_register_total", "The total number of account registration using Default.")
	PrometheusRegisterDefaultSuccessTotal = instrument.NewPrometheus().NewCounter(prometheusModuleName, "default_register_success_total", "The total number of success account registration using Default.")
	PrometheusRegisterDefaultFailedTotal  = instrument.NewPrometheus().NewCounter(prometheusModuleName, "default_register_failed_total", "The total number of failed account registration using Default.")

	PrometheusFacebookTotal                = instrument.NewPrometheus().NewCounter(prometheusModuleName, "facebook_total", "The total number of login using Facebook.")
	PrometheusFacebookSuccessTotal         = instrument.NewPrometheus().NewCounter(prometheusModuleName, "facebook_success_total", "The total number of success login using Facebook.")
	PrometheusFacebookFailedTotal          = instrument.NewPrometheus().NewCounter(prometheusModuleName, "facebook_failed_total", "The total number of failed login using Facebook.")
	PrometheusRegisterFacebookTotal        = instrument.NewPrometheus().NewCounter(prometheusModuleName, "facebook_register_total", "The total number of account registration using Facebook.")
	PrometheusRegisterFacebookSuccessTotal = instrument.NewPrometheus().NewCounter(prometheusModuleName, "facebook_register_success_total", "The total number of success account registration using Facebook.")
	PrometheusRegisterFacebookFailedTotal  = instrument.NewPrometheus().NewCounter(prometheusModuleName, "facebook_register_failed_total", "The total number of failed account registration using Facebook.")

	PrometheusGoogleTotal                = instrument.NewPrometheus().NewCounter(prometheusModuleName, "google_total", "The total number of login using Google.")
	PrometheusGoogleSuccessTotal         = instrument.NewPrometheus().NewCounter(prometheusModuleName, "google_success_total", "The total number of success login using Google.")
	PrometheusGoogleFailedTotal          = instrument.NewPrometheus().NewCounter(prometheusModuleName, "google_failed_total", "The total number of failed login using Google.")
	PrometheusRegisterGoogleTotal        = instrument.NewPrometheus().NewCounter(prometheusModuleName, "google_register_total", "The total number of account registration using Google.")
	PrometheusRegisterGoogleSuccessTotal = instrument.NewPrometheus().NewCounter(prometheusModuleName, "google_register_success_total", "The total number of success account registration using Google.")
	PrometheusRegisterGoogleFailedTotal  = instrument.NewPrometheus().NewCounter(prometheusModuleName, "google_register_failed_total", "The total number of failed account registration using Google.")
)

Functions

func APILoginHandler

func APILoginHandler(c echo.Context) error

APILoginHandler is a controller to handle new login request and returns access token in the response in JSON format

func APIRegisterHandler

func APIRegisterHandler(c echo.Context) error

APIRegisterHandler is a controller to handle new registration request and returns access token in the response in JSON format

func APIValidateAccessTokenHandler

func APIValidateAccessTokenHandler(c echo.Context) error

APIValidateAccessTokenHandler validates access token return true if parsed and validated, otherwise false

func MetricInitiateAccountRegistration

func MetricInitiateAccountRegistration(provider string)

MetricInitiateAccountRegistration increases the metric when there's a new account registration

func MetricInitiateAccountRegistrationFailed

func MetricInitiateAccountRegistrationFailed(provider string)

MetricInitiateAccountRegistrationFailed increases the metric when new account registration is success

func MetricInitiateAccountRegistrationSuccess

func MetricInitiateAccountRegistrationSuccess(provider string)

MetricInitiateAccountRegistrationSuccess increases the metric when new account registration is success

func MetricInitiateLogin

func MetricInitiateLogin(provider string)

MetricInitiateLogin increases the metric when iniate a login

func MetricLoginFailed

func MetricLoginFailed(provider string)

MetricLoginFailed increases the metric when login is failed

func MetricLoginSuccess

func MetricLoginSuccess(provider string)

MetricLoginSuccess increases the metric when login is success

func Migrate

func Migrate()

Migrate executes database auto-migrate schema Please note that the auto migrate will create tables, missing foreign keys, constraints, columns and indexes, and will change existing column’s type if it’s size, precision, nullable changed, it WON’T delete unused columns to protect your data

func New

func New(app *echo.Echo)

New initiates login module by registering the API endpoint into the server

func ProviderCallbackHandler

func ProviderCallbackHandler(c echo.Context) error

ProviderCallbackHandler is a callback handler to handle oauth redirect from service provider, usually service provider will include ?code=... that can be used to generate access token. And this handler will return an access token. If the login module redirect is TRUE, this handler will redirect to targer url and includes the access token, e.g. https://yourdomain.com?accessToken=...

func ProviderHandler

func ProviderHandler(c echo.Context) error

ProviderHandler is a handler for login using service provider. This handler will generate an oauth URI and redirect you to target service provider

Types

type AccountModel

type AccountModel struct {
	db.Model

	FirstName  string `gorm:"type:varchar(255);not null;"`
	LastName   string `gorm:"type:varchar(255)"`
	Email      string `gorm:"type:varchar(255);not null;index"`
	Password   string `gorm:"type:varchar(255);"`
	PicURL     string
	Birthday   *time.Time
	IsVerified bool `gorm:"default:FALSE"`

	AccountServiceProvider AccountServiceProviderModel `gorm:"foreignKey:AccountID"`
}

AccountModel is a schema for account

func (*AccountModel) TableName

func (m *AccountModel) TableName() string

TableName returns account table name

type AccountServiceProviderModel

type AccountServiceProviderModel struct {
	db.Model

	AccountID         uuid.UUID `gorm:"not null;"`
	ServiceProvider   string    `gorm:"type:varchar(20);not null;"`
	ServiceProviderID string    `gorm:"type:varchar(50);not null;"`
	PicURL            string
	Metadata          datatypes.JSON
}

AccountServiceProviderModel is a schema for account service provider

func (*AccountServiceProviderModel) TableName

func (m *AccountServiceProviderModel) TableName() string

TableName returns account service provider table name

type IRepository

type IRepository interface {
	FindOneByEmail(email string) (*AccountModel, error)
	Insert(account AccountModel) error
}

IRepository is an interface for login repository

var (
	LoginRepository IRepository
)

func NewRepository

func NewRepository() IRepository

NewRepository initiates login repository

type IService

type IService interface {
	SignInUsingServiceProvider(serviceProvider string, profile map[string]interface{}) error
	RegisterNewAccountUsingServiceProvider(serviceProvider string, profile map[string]interface{}) error

	RegisterNewAccount(newAccount ReqRegisterModel) error
	SignIn(loginReq ReqLoginModel) error

	GenerateAccessToken() (string, error)
}

IService is an interface for login service

func NewService

func NewService(loginRepository IRepository) IService

NewService initiates new login service

type Repository

type Repository struct {
	DB *gorm.DB
}

Repository is the implementation of login.IRepository

func (*Repository) FindOneByEmail

func (r *Repository) FindOneByEmail(email string) (*AccountModel, error)

FindOneByEmail returns account data filtered by email

func (*Repository) Insert

func (r *Repository) Insert(account AccountModel) error

Insert inserts new account data

type ReqLoginModel

type ReqLoginModel struct {
	Email    string `json:"email"`
	Password string `json:"password"`
}

ReqLoginModel is a schema for submitting login

func (ReqLoginModel) Validate

func (r ReqLoginModel) Validate() error

Validate validates login request

type ReqRegisterModel

type ReqRegisterModel struct {
	FirstName string `json:"first_name"`
	LastName  string `json:"last_name"`
	Email     string `json:"email"`
	Password  string `json:"password"`
}

ReqRegisterModel is a schema for submitting new account registration

func (ReqRegisterModel) Validate

func (r ReqRegisterModel) Validate() error

Validate validates registration submission

type Service

type Service struct {
	LoginRepository IRepository

	Account AccountModel
}

Service is the implementation of login.IService

func (*Service) GenerateAccessToken

func (s *Service) GenerateAccessToken() (string, error)

GenerateAccessToken returns access token in JWT format. The claim is based on data when being set in registration or login methods using the AccountModel.

func (*Service) RegisterNewAccount

func (s *Service) RegisterNewAccount(newAccount ReqRegisterModel) error

RegisterNewAccount returns nil if registration using default method is success.

func (*Service) RegisterNewAccountUsingServiceProvider

func (s *Service) RegisterNewAccountUsingServiceProvider(serviceProvider string, profile map[string]interface{}) error

RegisterNewAccountUsingServiceProvider returns nil when registration new account using service provider is succeded. This method will parse data from service provider and construct it using the AccountModel and AccountServiceModel. All data other than basic fields will be stored in AccountServiceModel.Metadata.

func (*Service) SignIn

func (s *Service) SignIn(loginReq ReqLoginModel) error

SignIn returns nil if email and password are verified

func (*Service) SignInUsingServiceProvider

func (s *Service) SignInUsingServiceProvider(serviceProvider string, profile map[string]interface{}) error

SignInUsingServiceProvider returns nil once the login or registration using service provider is succeeded