user

package module
v0.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 11, 2026 License: MIT Imports: 36 Imported by: 0

README

go-bolo/user

Users, authentication, OAuth2 and sessions for Go Bolo applications.

Go version

Overview

user is the official Go Bolo plugin for identity: it ships the default user model, the user REST API, password authentication with Redis-backed sessions, password recovery, Facebook login and an OAuth2 password grant with rotating refresh tokens — plus an optional JWT subplugin for stateless access tokens.

Features

  • User management — default user model, REST API (/api/user), role-based permissions (owner, manage_users, …), install/migration routines and template helpers.
  • Authentication — password login/logout, bcrypt credentials, auth sessions and tokens, forgot/reset/change-password flows with anti-enumeration responses, login throttling and reCAPTCHA helpers, auth email templates.
  • Sessions — Redis-backed cookie sessions with sliding expiration and one-shot flash messages.
  • Facebook login — OAuth code exchange for app clients (POST /auth/facebook/app-login-code).
  • OAuth2 password grant — token issuance, single-use rotating refresh tokens with theft containment, and RFC 7009 revocation.
  • OAuth2 JWT — optional stateless HS256 access tokens with the same refresh-token infrastructure.

Requirements

  • Go 1.23+
  • Go Bolo v1.1.5+
  • Redis (session store and OAuth2 token storage)

Installation

go get github.com/go-bolo/user

Quick start

Register the plugins with your Go Bolo app:

import (
    "github.com/go-bolo/bolo"
    user "github.com/go-bolo/user"
    auth_oauth2_password "github.com/go-bolo/user/oauth2_password"
    // optional JWT subplugin:
    // auth_oauth2_jwt "github.com/go-bolo/user/oauth2_jwt"
)

app := bolo.Init(opts)

app.RegisterPlugin(user.NewUserPlugin(&user.UserPluginCfg{}))
app.RegisterPlugin(auth_oauth2_password.NewPlugin(&auth_oauth2_password.PluginCfgs{}))
app.RegisterPlugin(user.NewAuthPlugin(&user.AuthPluginCfgs{}))
// optional, requires OAUTH2_JWT_SECRET:
// app.RegisterPlugin(auth_oauth2_jwt.NewPlugin(&auth_oauth2_jwt.PluginCfgs{}))

The auth plugin also registers the /login and /logout HTML pages and applies session + token authentication middleware to every request.

Configuration

All settings come from environment variables.

Facebook login
Key Type Default Description
SITE_FACEBOOK_APP_ID string "" Facebook app id
FACEBOOK_CLIENT_SECRET string "" Facebook app secret
FACEBOOK_REDIRECT_URI string "" Facebook redirect url

The endpoint returns 404 when the app id or secret is unset.

Sessions
Key Type Default Description
SITE_SESSION_ADDR_WRITER string "" Redis address for session writes
SITE_SESSION_ADDR_READER string "" Redis address for session reads
SITE_SESSION_PASSWORD string "" Redis password
SITE_SESSION_RESAVE bool true Resave the session (sliding expiration) on authenticated GETs
OAuth2 tokens
Key Type Default Description
OAUTH2_ACCESS_TOKEN_TTL duration 30m Access token lifetime
OAUTH2_REFRESH_IDLE_TTL duration 72h Refresh token idle timeout
OAUTH2_REFRESH_ABSOLUTE_TTL duration 720h Refresh token family absolute cap
OAUTH2_REFRESH_REUSE_GRACE duration 30s Replay grace window for rotated refresh tokens
OAUTH2_STRICT_401 bool false Reject anonymous requests with 401 + WWW-Authenticate

OAUTH2_ACCESS_TOKEN_EXPIRATION and OAUTH2_REFRESH_TOKEN_EXPIRATION (seconds) are accepted as legacy fallbacks.

JWT subplugin
Key Type Default Description
OAUTH2_JWT_SECRET string required HS256 signing secret — the plugin fails to start without it
OAUTH2_JWT_ISSUER string "" iss claim
OAUTH2_JWT_AUDIENCE string mm aud claim
OAUTH2_JWT_TTL duration 10m JWT lifetime
OAUTH2_JWT_LEEWAY duration 30s Clock-skew tolerance for exp/nbf

HTTP API

Key endpoints (see each feature's spec for the full contract):

Endpoint Description Docs
GET/POST /login, GET/POST /logout HTML session login/logout sessions
GET /auth/current Current user (public shape or {}) authentication
POST /auth/logout Logout + best-effort token revocation authentication
GET/POST /auth/forgot-password, GET/POST /auth/:userID/forgot-password/reset, POST /api/v2/auth/forgot-password/process Password recovery (3 steps) authentication
POST /api/v2/auth/change-password Change own password (API) authentication
GET/POST /api/user, GET/POST/PATCH/PUT/DELETE /api/user/:id, GET /api/user/count User CRUD with permissions user-management
GET /acl/permission, POST /acl/user/:userID/roles Roles and permissions user-management
POST /auth/facebook/app-login-code Facebook app-code login facebook-auth
POST /auth/grant-password/authenticate, POST /auth/grant-password/revoke OAuth2 password grant + revocation oauth2-password
POST /auth/jwt/authenticate, POST /auth/jwt/refresh-token JWT login + refresh oauth2-jwt

Documentation

Feature documentation lives in docs/ — each feature has a guide, spec and changelog:

Note: docs/ is excluded from the published Go module zip (via an empty docs/go.mod), so read it in the repository.

Development

go test ./...

Tests run against SQLite and an in-memory Redis (miniredis) — no external services required.

Contributing

Bug reports and pull requests are welcome on GitHub. For behavior changes, please open an issue first and reference the relevant feature spec under docs/.

License

MIT

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// SessionDB - Redis session connection for writes
	SessionDBWriter *redis.Client
	// SessionDB - Redis session connection for gets
	SessionDBReader *redis.Client
)

Functions

func AddEmailTemplates

func AddEmailTemplates(app bolo.App)

func AddFlashMessage

func AddFlashMessage(c echo.Context, m *FlashMessage) error

func CreateDefaultEmailTemplates

func CreateDefaultEmailTemplates(app bolo.App) error

func DeleteUserSession

func DeleteUserSession(c echo.Context) error

func FindOrCreateUserFromFacebook

func FindOrCreateUserFromFacebook(facebookUserDetails FacebookUserDetails, ctx *bolo.RequestContext) (*user_models.UserModel, error)

SignInUser Used for Signing In the Users

func GetFacebookOAuthConfig

func GetFacebookOAuthConfig(ctx *bolo.RequestContext) *oauth2.Config

GetFacebookOAuthConfig will return the config to call facebook Login

func HandleRequestSessionAuthentication

func HandleRequestSessionAuthentication(c echo.Context) error

func Init

func Init(app bolo.App)

Init - Start the redis session connection

func InstallAuth

func InstallAuth(app bolo.App) error

func SendRequestResetPasswordEmail

func SendRequestResetPasswordEmail(ctx *bolo.RequestContext, authToken *user_models.AuthTokenModel, u *user_models.UserModel, resetPrefixName string) (bool, error)

func SetUserSession

func SetUserSession(app bolo.App, c echo.Context, user bolo.UserInterface) (*sessions.Session, error)

func UserSettingsHandler

func UserSettingsHandler(c echo.Context) error

Types

type AuthController

type AuthController struct {
	App bolo.App
}

func NewAuthController

func NewAuthController(cfg *NewAuthControllerCFG) *AuthController

func (*AuthController) Activate

func (ctl *AuthController) Activate(c echo.Context) error

Activate a user account with activation code

func (*AuthController) ChangeOwnPassword

func (ctl *AuthController) ChangeOwnPassword(c echo.Context) error

ChangeOwnPassword - POST endpoint

func (*AuthController) ChangeOwnPasswordApi

func (ctl *AuthController) ChangeOwnPasswordApi(c echo.Context) error

func (*AuthController) ChangeOwnPassword_Page

func (ctl *AuthController) ChangeOwnPassword_Page(c echo.Context) error

func (*AuthController) CheckIfResetPasswordTokenIsValid

func (ctl *AuthController) CheckIfResetPasswordTokenIsValid(c echo.Context) error

Check if a reset token is valid

func (*AuthController) ForgotPasswordRequest

func (ctl *AuthController) ForgotPasswordRequest(c echo.Context) error

Generate one time reset password token and send it to user change password with token

func (*AuthController) ForgotPasswordUpdate

func (ctl *AuthController) ForgotPasswordUpdate(c echo.Context) error

func (*AuthController) ForgotPassword_Process

func (ctl *AuthController) ForgotPassword_Process(c echo.Context) error

ForgotPassword_Process - API step 3 to change password with token

func (*AuthController) ForgotPassword_Request

func (ctl *AuthController) ForgotPassword_Request(c echo.Context) error

ForgotPassword_Request - step 1 to change password

func (*AuthController) ForgotPassword_RequestWithIdentifier

func (ctl *AuthController) ForgotPassword_RequestWithIdentifier(c echo.Context) (err error)

ForgotPassword_RequestWithIdentifier - Step 1 to change password

func (*AuthController) ForgotPassword_ResetPage

func (ctl *AuthController) ForgotPassword_ResetPage(c echo.Context) error

ForgotPassword_ResetPage - step 2 to change password

func (*AuthController) GetCurrentUser

func (ctl *AuthController) GetCurrentUser(c echo.Context) error

func (*AuthController) Logout

func (ctl *AuthController) Logout(c echo.Context) error

Logout handler with supports to unAuthenticate from all strategies TODO! add support for unauthenticate from all session strategies with events

func (*AuthController) SetPassword

func (ctl *AuthController) SetPassword(c echo.Context) error

Set user password, usualy used by admins Current version dont need validation

func (*AuthController) Signup

func (ctl *AuthController) Signup(c echo.Context) error

func (*AuthController) UpdatePassword

func (ctl *AuthController) UpdatePassword(c echo.Context) error

type AuthPlugin

type AuthPlugin struct {
	bolo.Pluginer
	// a map with valid reset page prefix:
	ResetPrefixNames map[string]string

	AuthController         *AuthController
	SessionController      *SessionController
	FacebookAuthController *FacebookAuthController

	Name string

	SessionStore  sessions.Store // TODO! add more session store options as plugins
	SessionResave bool
}

func NewAuthPlugin

func NewAuthPlugin(cfg *AuthPluginCfgs) *AuthPlugin

func (*AuthPlugin) BindRoutes

func (r *AuthPlugin) BindRoutes(app bolo.App) error

func (*AuthPlugin) Bootstrap

func (p *AuthPlugin) Bootstrap(app bolo.App) error

func (*AuthPlugin) GetMigrations

func (p *AuthPlugin) GetMigrations() []*bolo.Migration

func (*AuthPlugin) GetName

func (p *AuthPlugin) GetName() string

func (*AuthPlugin) Init

func (p *AuthPlugin) Init(app bolo.App) error

func (*AuthPlugin) OnClose

func (p *AuthPlugin) OnClose(app bolo.App) error

func (*AuthPlugin) OnHTTPError

func (p *AuthPlugin) OnHTTPError(app bolo.App, e event.Event) error

type AuthPluginCfgs

type AuthPluginCfgs struct {
	ResetPrefixNames map[string]string
}

type ChangeOwnPasswordBody

type ChangeOwnPasswordBody struct {
	Password     string `json:"password,omitempty" form:"password"`
	NewPassword  string `json:"newPassword,omitempty" form:"newPassword" validate:"required,min=3"`
	RNewPassword string `json:"rNewPassword,omitempty" form:"rNewPassword" validate:"required,eqfield=NewPassword"`
}

func (*ChangeOwnPasswordBody) ToJSON

func (b *ChangeOwnPasswordBody) ToJSON() string

type Claims

type Claims struct {
	Email string
	jwt.RegisteredClaims
}

Claims is a struct that will be encoded to a JWT. jwt.RegisteredClaims is an embedded type to provide expiry time

type Controller

type Controller struct {
	App bolo.App
}

Http user controller | struct with http handlers

func NewController

func NewController(cfg *ControllerCfg) *Controller

func (*Controller) Count

func (ctl *Controller) Count(c echo.Context) error

func (*Controller) Create

func (ctl *Controller) Create(c echo.Context) error

func (*Controller) Delete

func (ctl *Controller) Delete(c echo.Context) error

func (*Controller) FindAllPageHandler

func (ctl *Controller) FindAllPageHandler(c echo.Context) error

func (*Controller) FindOne

func (ctl *Controller) FindOne(c echo.Context) error

func (*Controller) FindOnePageHandler

func (ctl *Controller) FindOnePageHandler(c echo.Context) error

func (*Controller) GetUserRoles

func (ctl *Controller) GetUserRoles(c echo.Context) error

func (*Controller) GetUserRolesAndPermissions

func (ctl *Controller) GetUserRolesAndPermissions(c echo.Context) error

func (*Controller) Query

func (ctl *Controller) Query(c echo.Context) error

func (*Controller) Update

func (ctl *Controller) Update(c echo.Context) error

func (*Controller) UpdateUserRoles

func (ctl *Controller) UpdateUserRoles(c echo.Context) error

type ControllerCfg

type ControllerCfg struct {
	App bolo.App
}

type CountJSONResponse

type CountJSONResponse struct {
	bolo.BaseMetaResponse
}

type EmptySuccessResponse

type EmptySuccessResponse struct {
	Messages []*bolo.ResponseMessage `json:"messages,omitempty"`
}

type ErrorResponse

type ErrorResponse struct {
	Code    int
	Message string
}

ErrorResponse is struct for sending error message with code.

type FacebookAuthController

type FacebookAuthController struct {
}

func (*FacebookAuthController) LoginWithFacebookAppCode

func (ctl *FacebookAuthController) LoginWithFacebookAppCode(c echo.Context) error

type FacebookUserDetails

type FacebookUserDetails struct {
	ID      string               `json:"id"`
	Name    string               `json:"name"`
	Email   string               `json:"email"`
	Picture *FacebookUserPicture `json:"picture"`
}

FacebookUserDetails is struct used for user details

func GetUserInfoFromFacebook

func GetUserInfoFromFacebook(token string, ctx *bolo.RequestContext) (FacebookUserDetails, error)

GetUserInfoFromFacebook will return information of user which is fetched from facebook

type FacebookUserPicture

type FacebookUserPicture struct {
	Data struct {
		Height       int    `json:"height"`
		IsSilhouette bool   `json:"is_silhouette"`
		URL          string `json:"url"`
		Width        int    `json:"width"`
	} `json:"data"`
}

type FindOneJSONResponse

type FindOneJSONResponse struct {
	Record *user_models.UserModel `json:"user"`
}

type FlashMessage

type FlashMessage struct {
	Type    string `json:"type"`
	Message string `json:"message"`
	Field   string `json:"field"`
	Tag     string `json:"tag"`
}

func (*FlashMessage) ToJSON

func (m *FlashMessage) ToJSON() []byte

type FlashMessageTPL

type FlashMessageTPL struct {
	Ctx     *bolo.RequestContext
	Message *FlashMessage
}

type FlashMessages

type FlashMessages []*FlashMessage

func GetFlashMessages

func GetFlashMessages(c echo.Context) (messages FlashMessages, err error)

type ForgotPasswordChange_RequestBody

type ForgotPasswordChange_RequestBody struct {
	Email           string `json:"email" form:"email" validate:"required,email"`
	ResetPrefixName string `json:"reset_prefix_name" form:"reset_prefix_name"`
}

type ForgotPassword_Process_RequestBody

type ForgotPassword_Process_RequestBody struct {
	Token            string      `json:"token" form:"token" validate:"required"`
	UserID           json.Number `json:"userID" form:"userID" validate:"required"`
	NewPassword      string      `json:"newPassword" form:"newPassword" validate:"required,min=3"`
	RNewPassword     string      `json:"rNewPassword" form:"rNewPassword" validate:"required,eqfield=NewPassword"`
	RedirectOnSucess string      `json:"redirectOnSucess" form:"redirectOnSucess"`
}

type HTMLBootstrapConfig

type HTMLBootstrapConfig struct {
	AppName           string               `json:"appName"`
	ENV               string               `json:"env"`
	Site              string               `json:"site"`
	Hostname          string               `json:"hostname"`
	QueryDefaultLimit int                  `json:"queryDefaultLimit"`
	QueryMaxLimit     int                  `json:"queryMaxLimit"`
	Locales           []string             `json:"locales"`
	DefaultLocale     string               `json:"defaultLocale"`
	Date              clientSideDateFormat `json:"date"`
	Plugins           []string             `json:"plugins"`
	User              map[string]string    `json:"authenticatedUser"`
	UserRoles         []string             `json:"userRoles"`
	ActiveLocale      string               `json:"activeLocale"`
}

type ListJSONResponse

type ListJSONResponse struct {
	bolo.BaseListReponse
	Record *[]*user_models.UserModel `json:"user"`
}

type LoginRequestBody

type LoginRequestBody struct {
	Email      string `json:"email" form:"email" validate:"required"`
	Password   string `json:"password" form:"password" validate:"required"`
	RememberMe bool   `json:"remember_me" form:"remember_me"`
}

type LoginWithFacebookAppCodeBodyRequest

type LoginWithFacebookAppCodeBodyRequest struct {
	Code        string `json:"code"`
	RedirectUri string `json:"redirect_uri"`
}

type LogoutRequestBody

type LogoutRequestBody struct {
	RefreshToken string `json:"refresh_token"`
}

LogoutRequestBody corpo opcional do logout: permite revogar também o refresh token da sessão.

type NewAuthControllerCFG

type NewAuthControllerCFG struct {
	App bolo.App
}

type NewFacebookAuthControllerCFG

type NewFacebookAuthControllerCFG struct {
	App bolo.App
}

type NewSessionControllerCFG

type NewSessionControllerCFG struct {
	App bolo.App
}

type RequestBody

type RequestBody struct {
	Record *user_models.UserModel `json:"user"`
}

type RoleTableItem

type RoleTableItem struct {
	Name    string `json:"name"`
	Checked bool   `json:"checked"`
	Role    string `json:"role"`
}

type SessionController

type SessionController struct {
	App bolo.App
}

func NewSessionController

func NewSessionController(cfg *NewSessionControllerCFG) *SessionController

func (*SessionController) Login

func (ctl *SessionController) Login(c echo.Context) error

func (*SessionController) LoginPage

func (ctl *SessionController) LoginPage(c echo.Context) error

func (*SessionController) Logout

func (ctl *SessionController) Logout(c echo.Context) error

type SessionData

type SessionData struct {
	UserID string `json:"userId"`
}

func (*SessionData) ToJSON

func (sd *SessionData) ToJSON() string

type SetPasswordBody

type SetPasswordBody struct {
	NewPassword  string `json:"newPassword,omitempty" validate:"required,min=3"`
	RNewPassword string `json:"rNewPassword,omitempty" validate:"required,eqfield=NewPassword"`
}

func (*SetPasswordBody) ToJSON

func (b *SetPasswordBody) ToJSON() string

type SignupBody

type SignupBody struct {
	Username     string `json:"username,omitempty" validate:"required"`
	Email        string `json:"email,omitempty" validate:"required,email"`
	ConfirmEmail string `json:"confirmEmail,omitempty" validate:"required,email,eqcsfield=Email"`
	DisplayName  string `json:"displayName,omitempty" validate:"required"`
	FullName     string `json:"fullName,omitempty"`
	Biography    string `json:"biography,omitempty"`
	Gender       string `json:"gender,omitempty"`
	Language     string `json:"language,omitempty"`
	AcceptTerms  bool   `json:"acceptTerms,omitempty" validate:"required"`
	Birthdate    string `json:"birthdate,omitempty"`
	Phone        string `json:"phone,omitempty"`
}

func (*SignupBody) ToJSON

func (sb *SignupBody) ToJSON() string

type SignupResponse

type SignupResponse struct {
	User   *user_models.UserModel       `json:"user"`
	Errors []*bolo.ValidationFieldError `json:"errors,omitempty"`
}

type SuccessResponse

type SuccessResponse struct {
	Code     int
	Message  string
	Response interface{}
}

SuccessResponse is struct for sending error message with code.

type TeaserTPL

type TeaserTPL struct {
	Ctx    *bolo.RequestContext
	Record *user_models.UserModel
}

type UserDetails

type UserDetails struct {
	Name     string
	Email    string
	Password string
}

UserDetails is struct used for user details

type UserPlugin

type UserPlugin struct {
	bolo.Pluginer
	Controller *Controller

	Name string
}

func NewUserPlugin

func NewUserPlugin(cfg *UserPluginCfg) *UserPlugin

func (*UserPlugin) BindRoutes

func (r *UserPlugin) BindRoutes(app bolo.App) error

func (*UserPlugin) GetMigrations

func (p *UserPlugin) GetMigrations() []*bolo.Migration

func (*UserPlugin) GetName

func (r *UserPlugin) GetName() string

func (*UserPlugin) Init

func (r *UserPlugin) Init(app bolo.App) error

type UserPluginCfg

type UserPluginCfg struct{}

type UserRolesBodyRequest

type UserRolesBodyRequest struct {
	UserRoles []string `json:"userRoles"`
}

type UserRolesResponse

type UserRolesResponse struct {
	Roles       map[string]*acl.Role `json:"roles"`
	Permissions string               `json:"permissions"`
}

Directories

Path Synopsis
migrations

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL