steranko

package module
v0.26.0 Latest Latest
Warning

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

Go to latest
Published: Jun 27, 2026 License: Apache-2.0 Imports: 11 Imported by: 9

README

Steranko 🔐

GoDoc Version Build Status Go Report Card Codecov

Website Authentication/Authorization for Go

Steranko is an embeddable library that manages user authentication, and authorization. You can configure it at run time (or compile time) to meet your specific project needs.

To use Steranko, you implement two interfaces in your code — a UserService (CRUD for your user records) and a KeyService (the keys that sign JWT tokens) — then wire Steranko's handlers into your HTTP server.

// userService and keyService are YOUR implementations of the
// steranko.UserService and steranko.KeyService interfaces.
s := steranko.New(
    userService,
    keyService,
    steranko.WithPasswordSchema(schema.New(schema.String{MinLength: 20, Required: true})),
    steranko.WithPasswordHasher(hash.BCrypt(15)),
)

// Wire the handlers into an Echo server.
e := echo.New()
e.POST("/signin", func(ctx echo.Context) error {
    _, err := s.SigninFormPost(ctx)
    return err
})
e.POST("/signout", func(ctx echo.Context) error {
    s.SignOut(ctx)
    return nil
})

// Protect routes with the middleware, then read the authenticated claims.
e.GET("/profile", profileHandler, s.Middleware)

DO NOT USE

This project is a work-in-progress, and should NOT be used by ANYONE, for ANY PURPOSE, under ANY CIRCUMSTANCES. It is GUARANTEED to blow up your computer, send your cat into an infinite loop, and combine your hot and cold laundry into a single cycle.

Project Goals

  • Create a configurable, open source authentication/authorization system in Go.

  • Hashed passwords using bcrypt

  • Automatically upgrade password encryption cost on signin.

  • Lock out user accounts after N failed attempts.

  • Maintain security with JWT tokens

  • Password strength checking (via JSON-Schema extensions)

  • Password vulnerability via HaveIBeenPwned API.

Possible future additions
  • Middleware tracks and blocks malicious users

    • Errors (like 404, and 500) have an associated number of points.
    • Track points per user/ip address with leaky bucket algorithm
    • Block users with a certain number of points
    • Ban users/ip addresses for repeated policy violations
    • Admin console allows tweaking of rules, reinstatement of banned accounts.
  • Identify malicious users with a (relatively) invisible CAPTCHA system

    • Track javascript events during signup (keyup, keydown, mousemove, click)
    • Track timing of events. They must not be too fast, or too consistent.
    • Something to prevent requests from being forwarded to an actual human.
    • Math problems?
    • Geolocation.

What matters here

  • User.SetPassword takes a ciphertext, never a plaintext. The User interface stores whatever string it is handed. Always hash first by calling the Steranko.SetPassword helper (which runs the configured PasswordHasher); calling user.SetPassword with a raw password persists cleartext and breaks every later signin.

  • The hasher list is ordered: index 0 is primary, the rest are deprecated. A password matched by any non-primary hasher is transparently re-hashed with the primary on the next signin (the Rehash/upgrade path). This is how bcrypt cost upgrades roll out — keep old hashers in the list until every user has signed in.

  • hash.Plaintext is for development only and silently makes hashing a no-op. Because plaintext "hashes" equal the password, tests that use it cannot detect a missing-hash bug. Test hashing-sensitive code paths against hash.BCrypt instead.

  • Failed signins are deliberately slow and constant-time. crypto/rand jitter plus a cached decoy hash (decoyPasswordHash) keep a missing account indistinguishable from a wrong password, defeating username enumeration. Don't "optimize" these delays away.

  • Cookie names depend on TLS. Secure requests use the __Host-Authorization prefix (domain-locked, HTTPS-only); plain HTTP uses Authorization. Signin and signout must agree on the name, which is why both route through cookieName.

  • JWT methods are allow-listed to HMAC only (JWTValidMethods: HS256/384/512). This blocks the alg:none and algorithm-confusion attacks; don't widen it without reason.

Pull Requests Welcome

Steranko is a work in progress, and will benefit from your experience reports, use cases, and contributions. If you have an idea for making this library better, send in a pull request. We're all in this together! 🔐

Documentation

Overview

Package steranko provides embeddable user authentication and authorization for Go web applications, including password hashing, validation rules, and JWT-based session cookies.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func JWTValidMethods added in v0.22.0

func JWTValidMethods() jwt.ParserOption

JWTValidMethods returns a jwt.ParserOption that restricts the JWT parser to only accept secure encryption methods defined in the golang-jwt package. https://pkg.go.dev/github.com/golang-jwt/jwt/v5@v5.2.1#WithValidMethods

func Middleware added in v0.4.2

func Middleware(factory Factory) echo.MiddlewareFunc

Middleware is a standalone middleware that works for multi-tenant environments, where you may need to use a factory to load the specific steranko settings depending on the domain being called.

Types

type Config

type Config struct {
	PasswordSchema schema.Schema `json:"passwordSchema"` // JSON-encoded schema for password validation rules.
}

Config holds the file-loadable settings for a Steranko instance.

type Context added in v0.3.0

type Context struct {
	echo.Context
	// contains filtered or unexported fields
}

Context extends the echo context with an authenticated JWT Token.

func (*Context) Authorization added in v0.4.0

func (ctx *Context) Authorization() (jwt.Claims, error)

Authorization retrieves the JWT token claims from the context. Values are cached so we don't re-parse the JWT cookie with multiple calls.

type Factory added in v0.4.2

type Factory interface {

	// Steranko retrieves the correct instance to use
	// for this domain or returns an error
	Steranko(ctx echo.Context) (*Steranko, error)
}

Factory is used in multi-tenant environments to locate the steranko instance that will be used (based on the context)

type KeyService added in v0.3.0

type KeyService interface {

	// GetCurrentKey returns the current JWT key in use by the server
	GetCurrentKey() (string, any, error)

	// FindKey returns the key associated with the given JWT token.
	FindKey(*jwt.Token) (any, error)
}

KeyService is an interface that the calling application must implement in order to use Steranko. The KeyService manages the encryption keys that sign and verify JWT tokens.

type NilSigninService added in v0.24.0

type NilSigninService struct{}

NilSigninService is an empty implementation of SigninService that does nothing. It can be used as a default or placeholder implementation when no actual signin service is needed.

func (NilSigninService) IsSigninLocked added in v0.24.0

func (s NilSigninService) IsSigninLocked(request *http.Request, username string) bool

IsSigninLocked always reports that the account is not locked.

func (NilSigninService) SigninFailure added in v0.24.0

func (s NilSigninService) SigninFailure(request *http.Request, username string)

SigninFailure does nothing.

func (NilSigninService) SigninSuccess added in v0.24.0

func (s NilSigninService) SigninSuccess(request *http.Request, username string)

SigninSuccess does nothing.

type Option added in v0.16.0

type Option func(*Steranko)

Option is a functional option that configures a Steranko instance at construction time.

func WithConfigFile added in v0.16.0

func WithConfigFile(config Config) Option

WithConfigFile loads the values from a configuration file into this Steranko instance.

func WithPasswordHasher added in v0.16.0

func WithPasswordHasher(hashers ...PasswordHasher) Option

WithPasswordHasher sets the hashing algorithm(s) to use when setting/validating passwords. The first hasher in the list is used to create new passwords. All subsequent hashers are "deprecated" and will be upgraded to the primary algorithm the next time the user signs in.

func WithPasswordRules added in v0.16.0

func WithPasswordRules(passwordRules ...PasswordRule) Option

WithPasswordRules appends the provided password rules to the list used when setting new passwords.

func WithPasswordSchema added in v0.16.0

func WithPasswordSchema(passwordSchema schema.Schema) Option

WithPasswordSchema sets the provided schema.Schema as the validation function when setting new passwords. Default is (minimum length: 8 characters)

func WithSigninService added in v0.24.0

func WithSigninService(service SigninService) Option

WithSigninService sets the SigninService to use when tracking signin successes and failures. This related to the "MaxSigninFailures" and "SigninLockoutMinutes" options, which lock out users after too many failed signin attempts.

type PasswordHasher added in v0.16.0

type PasswordHasher interface {

	// ID returns a string that uniquely identifies this plugin.
	ID() string

	// HashPassword returns a hashed value that can be safely stored in a database.
	HashPassword(plaintext string) (ciphertext string, err error)

	// CompareHashedPassword checks that a plaintext password matches a stored ciphertext value.
	// OK returns TRUE if the values match.  Rehash returns TRUE if the hashing criteria has
	// changed and the password should be re-hashed and stored in its place.
	CompareHashedPassword(ciphertext string, plaintext string) (OK bool, Rehash bool)
}

PasswordHasher handles all encryption functions for passwords.

type PasswordRule added in v0.16.0

type PasswordRule interface {

	// ID returns a string that uniquely identifies this plugin.
	ID() string

	// PasswordRuleDescription returns a human-readable string that explains how the password can be used.
	PasswordRuleDescription() string

	// ValidatePassword returns TRUE if the password can be used in this system.  If not, it returns FALSE, and a message explaining why
	ValidatePassword(password string) (OK bool, errorMessage string)
}

PasswordRule is used to verify if a password meets the password complexity criteria for this system.

type RequestPasswordResetResponse added in v0.2.0

type RequestPasswordResetResponse struct {
}

RequestPasswordResetResponse is the response returned after a password reset request.

type RequestPasswordResetTransaction

type RequestPasswordResetTransaction struct {
	Username string `json:"username" form:"username"` // public username of the person requesting the reset.
}

RequestPasswordResetTransaction is the request body for initiating a password reset.

type SigninResponse added in v0.2.0

type SigninResponse struct {
	Username     string
	JWT          string
	ErrorMessage string
	Error        error
}

SigninResponse includes all the information returned by Steranko after a signin request.

type SigninService added in v0.24.0

type SigninService interface {

	// SigninSuccess reports a successful signin to the database.
	// This method SHOULD reset the signin failure count for the user.
	SigninSuccess(request *http.Request, username string)

	// SigninFailure reports a failed signin to the database.
	// This method SHOULD increment the signin failure count for the user.
	SigninFailure(request *http.Request, username string)

	// IsSigninLocked returns TRUE if the user is currently locked out due to too many signin failures.
	IsSigninLocked(request *http.Request, username string) bool
}

SigninService wraps all of the functions that must be provided to Steranko by your application.

type SigninTransaction

type SigninTransaction struct {
	Username      string `json:"username"      form:"username"`      // public username for this person
	Password      string `json:"password"      form:"password"`      // private (hashed?) password for this person
	TwoFactorCode string `json:"twoFactorCode" form:"twoFactorCode"` // [Optional] 2FA code to send to the 2FA plugin
}

SigninTransaction includes all of the information that MUST be posted to Sterenko in order to sign in to the system.

type Steranko

type Steranko struct {
	// contains filtered or unexported fields
}

Steranko contains all required configuration information for this library.

func New

func New(userService UserService, keyService KeyService, options ...Option) *Steranko

New returns a fully initialized Steranko instance, with HandlerFuncs that support all of your user authentication and authorization needs.

func (*Steranko) ApproveRequest added in v0.4.2

func (s *Steranko) ApproveRequest(ctx echo.Context) error

ApproveRequest will (in the future) apply filtering rules to requests and block any that should not be allowed.

func (*Steranko) ComparePassword added in v0.16.0

func (s *Steranko) ComparePassword(plaintext string, hashedValue string) (bool, bool)

ComparePassword tries to validate the plaintext password and hashedValue using each of the password hashers in sequence. If the password matches THE PRIMARY hasher, then this returns TRUE, FALSE. If the password matches any of THE BACKUP hashers, then this returns TRUE, TRUE. If the password does not match any of the hashers then this returns FALSE, FALSE.

func (*Steranko) Context added in v0.22.1

func (s *Steranko) Context(ctx echo.Context) *Context

Context returns a new steranko.Context that wraps the provided echo.Context and embeds this Steranko instance.

func (*Steranko) CreateJWT added in v0.16.0

func (s *Steranko) CreateJWT(claims jwt.Claims) (string, error)

CreateJWT generates a new JWT token using the specified claims. Steranko writes this JWT token using the HS512 signing method, and the signing key that is generated by the embedded KeyService.

func (*Steranko) GetAuthorization added in v0.16.0

func (s *Steranko) GetAuthorization(request *http.Request) (jwt.Claims, error)

GetAuthorization retrieves the JWT token claims from the request.

func (*Steranko) Middleware added in v0.3.0

func (s *Steranko) Middleware(next echo.HandlerFunc) echo.HandlerFunc

Middleware wraps the original echo context with the Steranko context.

func (*Steranko) PostPasswordToken

func (s *Steranko) PostPasswordToken(ctx echo.Context) error

PostPasswordToken implements the http.HandlerFunc signature, and should be wired in to your REST API to allow users to tell the server that they forgot their password. This should initiate some way for the system to send them a one time token to create a new password.

func (*Steranko) PostPasswordUpdate

func (s *Steranko) PostPasswordUpdate(ctx echo.Context) error

PostPasswordUpdate implements the http.HandlerFunc signature, and should be wired in to your REST API to allow users to update their passwords.

func (*Steranko) SetCookie added in v0.22.0

func (s *Steranko) SetCookie(ctx echo.Context, claims jwt.Claims) error

SetCookie writes a Cookie / JWT token to the User's browser using the provided claims.

func (*Steranko) SetPassword added in v0.17.0

func (s *Steranko) SetPassword(user User, plaintext string) error

SetPassword hashes the provided plaintext password and sets it on the User.

func (*Steranko) SignOut added in v0.3.2

func (s *Steranko) SignOut(ctx echo.Context) bool

SignOut implements the echo.HandlerFunc, and can be used directly in your REST API, or can be wrapped by your own custom function. It returns TRUE if the user had a backup cookie that has been restored, and FALSE if the user is now completely signed out.

func (*Steranko) SigninFormPost added in v0.22.0

func (s *Steranko) SigninFormPost(ctx echo.Context) (User, error)

SigninFormPost reads the data from a form post and signs in the user using their username/password. If the signin is successful it automatically sets the "Authorization" cookie in the user's browser. If unsuccessful, an error is returned to the caller.

func (*Steranko) SigninUser added in v0.22.0

func (s *Steranko) SigninUser(ctx echo.Context, user User) error

SigninUser writes a cookie to the User's browser that signs them into the server.

func (*Steranko) ValidatePassword

func (s *Steranko) ValidatePassword(plaintext string) error

ValidatePassword checks a password against all system requirements

func (*Steranko) WithOptions added in v0.16.0

func (s *Steranko) WithOptions(options ...Option)

WithOptions applies the provided Option functions to this Steranko instance.

This mutates the instance without synchronization and is therefore NOT safe to call concurrently with request handling. Apply all options during construction (via New, or immediately after) before the Steranko is shared across goroutines.

type UpdatePasswordResponse added in v0.2.0

type UpdatePasswordResponse struct {
}

UpdatePasswordResponse is the response returned after a password update.

type UpdatePasswordTransaction

type UpdatePasswordTransaction struct {
	Username    string `json:"username"    form:"username"`
	OldPassword string `json:"oldPassword" form:"oldPassword"`
	NewPassword string `json:"newPassword" form:"newPassword"`
}

UpdatePasswordTransaction is the request body for changing a user's password.

type User

type User interface {
	GetUsername() string // Returns the username of the User
	GetPassword() string // Returns the password of the User

	SetUsername(username string)   // Sets the username of the User
	SetPassword(ciphertext string) // Sets the password of the User
}

User interface wraps all of the functions that Steranko needs to authorize a user of the system. This is done so that Steranko can be retrofitted on to your existing data objects. Just implement this interface, and a CRUD service, and you're all set.

type UserService

type UserService interface {

	// New creates a newly initialized User that is ready to use
	New() User

	// Load retrieves a single User from the database
	Load(username string, user User) error

	// Save inserts/updates a single User in the database
	Save(user User, comment string) error

	// Delete removes a single User from the database
	Delete(user User, comment string) error

	// RequestPasswordReset handles the application-specific details of
	// delivering a password reset message to the user.
	RequestPasswordReset(user User) error

	// NewClaims generates an empty jwt.Claims object.
	NewClaims() jwt.Claims

	// Claims generates a jwt.Claims object for the given user.
	Claims(user User) (jwt.Claims, error)

	// Close cleans up any connections opened by the service.
	Close()
}

UserService wraps all of the functions that must be provided to Steranko by your application.

Directories

Path Synopsis
plugin
hash
Package hash provides password hashing algorithm plugins for Steranko.
Package hash provides password hashing algorithm plugins for Steranko.
haveibeenpwned
Package haveibeenpwned provides a Steranko password rule that rejects passwords found in known data breaches, via the HaveIBeenPwned.com API.
Package haveibeenpwned provides a Steranko password rule that rejects passwords found in known data breaches, via the HaveIBeenPwned.com API.
rule
Package rule provides password-complexity validation plugins for Steranko.
Package rule provides password-complexity validation plugins for Steranko.

Jump to

Keyboard shortcuts

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