multisession

package
v0.27.2 Latest Latest
Warning

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

Go to latest
Published: Aug 31, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// EventListDeviceSessionsBefore is emitted before querying device sessions for a set of tokens.
	EventListDeviceSessionsBefore = "multisession:list:before"

	// EventListDeviceSessionsAfter is emitted after successfully retrieving device sessions.
	EventListDeviceSessionsAfter = "multisession:list:after"

	// EventSetActiveSessionBefore is emitted before establishing a session as the primary active session.
	EventSetActiveSessionBefore = "multisession:set_active:before"

	// EventSetActiveSessionAfter is emitted after successfully activating a device session.
	EventSetActiveSessionAfter = "multisession:set_active:after"

	// EventRevokeDeviceSessionBefore is emitted before revoking a device session.
	EventRevokeDeviceSessionBefore = "multisession:revoke:before"

	// EventRevokeDeviceSessionAfter is emitted after successfully revoking a device session.
	EventRevokeDeviceSessionAfter = "multisession:revoke:after"

	// EventSessionCreated is emitted after a new multi-session is registered on a device.
	EventSessionCreated = "multisession:session_created"

	// EventSignOut is emitted when all multi-sessions registered on a device are mass-revoked during sign-out.
	EventSignOut = "multisession:sign_out"
)
View Source
const PluginID = "multi-session"

PluginID is the unique string identifier for the MultiSession plugin ("multi-session").

Variables

View Source
var (
	// ErrInvalidSessionToken indicates that the provided session token or cookie signature is invalid.
	ErrInvalidSessionToken = errors.New("multisession: invalid session token")

	// ErrSessionNotFound indicates that the requested session does not exist or has expired.
	ErrSessionNotFound = errors.New("multisession: session not found")

	// ErrSecretRequired indicates that a cryptographic secret is required to sign or verify cookies.
	ErrSecretRequired = errors.New("multisession: secret key is required")

	// ErrInvalidSignature indicates an invalid or forged HMAC signature on a multi-session cookie.
	ErrInvalidSignature = errors.New("multisession: invalid cookie signature")
)

Functions

func SignCookieValue

func SignCookieValue(tokenValue, secret string) string

SignCookieValue generates a signed cookie string in the format "<token>.<signature>" using HMAC-SHA256.

func VerifyCookieValue

func VerifyCookieValue(signedCookieVal, secret string) (string, error)

VerifyCookieValue verifies an HMAC-SHA256 signature and returns the raw token value. It supports optional "s:" prefix used by TypeScript signed cookie implementations.

Types

type Config

type Config struct {
	// MaximumSessions specifies the maximum number of active concurrent multi-sessions allowed on a single device.
	// Default: 5
	MaximumSessions int

	// CookiePrefix defines the prefix for multi-session cookies.
	// Default: "modular-auth"
	CookiePrefix string

	// Secret is the HMAC SHA-256 secret key used for signing and verifying multi-session cookies.
	Secret string

	// OnSessionActivated is an optional callback triggered after a session is set active.
	OnSessionActivated SessionActivatedCallback

	// OnSessionRevoked is an optional callback triggered after a session is revoked.
	OnSessionRevoked SessionRevokedCallback
}

Config defines the configuration parameters for the MultiSession plugin.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns a Config struct initialized with recommended default values.

type DeviceSession

type DeviceSession struct {
	Session  entity.Session `json:"session"`
	User     entity.User    `json:"user"`
	IsActive bool           `json:"isActive"`
}

DeviceSession pairs a Session entity with its corresponding User entity for device session listing, including a flag indicating whether it is the currently active primary session.

type ListDeviceSessionsEventPayload

type ListDeviceSessionsEventPayload struct {
	Params *ListDeviceSessionsParams
	Result *ListDeviceSessionsResult
	Extra  map[string]any
}

ListDeviceSessionsEventPayload contains parameter and result data associated with device session listing lifecycle events.

type ListDeviceSessionsParams

type ListDeviceSessionsParams struct {
	// Tokens is the slice of verified multi-session tokens present on the client device.
	Tokens []string `json:"tokens"`

	// ActiveToken optionally specifies the raw token string of the currently active primary session.
	ActiveToken string `json:"activeToken,omitempty"`
}

ListDeviceSessionsParams contains input parameters for listing device sessions.

type ListDeviceSessionsResult

type ListDeviceSessionsResult struct {
	// DeviceSessions is the slice of valid, non-expired sessions on the device.
	DeviceSessions []DeviceSession `json:"deviceSessions"`

	// TotalCount is the total number of valid multi-sessions found.
	TotalCount int `json:"totalCount"`

	// ActiveSession points to the currently active primary session on the device, if present in the list.
	ActiveSession *DeviceSession `json:"activeSession,omitempty"`
}

ListDeviceSessionsResult contains the list of active device sessions and metadata.

type MultiSessionConfigInfo

type MultiSessionConfigInfo struct {
	MaximumSessions int    `json:"maximumSessions"`
	CookiePrefix    string `json:"cookiePrefix"`
}

MultiSessionConfigInfo represents public metadata regarding active plugin configuration.

type Option

type Option func(*Config)

Option defines a functional option type for configuring the plugin.

func WithCookiePrefix

func WithCookiePrefix(prefix string) Option

WithCookiePrefix configures the custom prefix used for multi-session cookies.

func WithMaximumSessions

func WithMaximumSessions(max int) Option

WithMaximumSessions configures the maximum session limit per device.

func WithOnSessionActivated

func WithOnSessionActivated(fn SessionActivatedCallback) Option

WithOnSessionActivated sets an optional callback executed after a session is set active.

func WithOnSessionRevoked

func WithOnSessionRevoked(fn SessionRevokedCallback) Option

WithOnSessionRevoked sets an optional callback executed after a session is revoked.

func WithSecret

func WithSecret(secret string) Option

WithSecret configures the cryptographic secret key used for HMAC cookie signature verification.

type Plugin

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

Plugin implements the MultiSession plugin for go-modular-auth.

func New

func New(repo Repository, opts ...Option) *Plugin

New instantiates a new MultiSession plugin configured with the given repository and options.

func (*Plugin) AfterSessionCreated

func (p *Plugin) AfterSessionCreated(ctx context.Context, w http.ResponseWriter, r *http.Request, newSession *entity.Session) error

AfterSessionCreated runs after a new session is created to enforce session limits and emit multi-session cookies.

func (*Plugin) AfterSignOut

func (p *Plugin) AfterSignOut(ctx context.Context, w http.ResponseWriter, r *http.Request) error

AfterSignOut runs during sign-out to perform mass revocation of all multi-sessions registered on the device.

func (*Plugin) Config

func (p *Plugin) Config() Config

Config returns the active configuration of the MultiSession plugin.

func (*Plugin) ExpireCookie

func (p *Plugin) ExpireCookie(w http.ResponseWriter, cookieName string)

ExpireCookie marks a specified cookie name for immediate expiration in an HTTP response.

func (*Plugin) ExpireMainSessionCookie

func (p *Plugin) ExpireMainSessionCookie(w http.ResponseWriter)

ExpireMainSessionCookie marks the primary session cookie for immediate expiration in an HTTP response.

func (*Plugin) ExtractMainSessionToken

func (p *Plugin) ExtractMainSessionToken(r *http.Request) string

ExtractMainSessionToken extracts and verifies the primary session token cookie from an incoming HTTP request.

func (*Plugin) ExtractMultiSessionTokens

func (p *Plugin) ExtractMultiSessionTokens(r *http.Request) []string

ExtractMultiSessionTokens parses and verifies all multi-session cookies present on an incoming HTTP request.

func (*Plugin) GetConfigInfo

func (p *Plugin) GetConfigInfo() MultiSessionConfigInfo

GetConfigInfo returns a MultiSessionConfigInfo struct containing active public configuration settings.

func (*Plugin) GetMultiCookieName

func (p *Plugin) GetMultiCookieName(token string) string

GetMultiCookieName formats and sanitizes the multi-session cookie name for a given token string.

func (*Plugin) ID

func (p *Plugin) ID() string

ID returns the unique identifier for the MultiSession plugin ("multi-session").

func (*Plugin) Init

func (p *Plugin) Init(ctx *plugin.Context) error

Init initializes the plugin with the shared execution context.

func (*Plugin) ListDeviceSessions

func (p *Plugin) ListDeviceSessions(ctx context.Context, params ListDeviceSessionsParams) (*ListDeviceSessionsResult, error)

ListDeviceSessions queries and returns all valid, non-expired device sessions for the given parameters.

func (*Plugin) Repository

func (p *Plugin) Repository() Repository

Repository returns the active storage repository instance.

func (*Plugin) RevokeAllSessions

func (p *Plugin) RevokeAllSessions(ctx context.Context, params RevokeAllSessionsParams) (*RevokeAllSessionsResult, error)

RevokeAllSessions revokes all multi-sessions registered on a device.

func (*Plugin) RevokeDeviceSession

func (p *Plugin) RevokeDeviceSession(ctx context.Context, params RevokeDeviceSessionParams) (*RevokeDeviceSessionResult, error)

RevokeDeviceSession revokes a single session, all sessions, or all other non-active sessions based on params.

func (*Plugin) RevokeOtherSessions

func (p *Plugin) RevokeOtherSessions(ctx context.Context, params RevokeOtherSessionsParams) (*RevokeOtherSessionsResult, error)

RevokeOtherSessions revokes all device sessions except the currently active primary session.

func (*Plugin) SetActiveSession

func (p *Plugin) SetActiveSession(ctx context.Context, params SetActiveSessionParams) (*SetActiveSessionResult, error)

SetActiveSession activates a target device session specified in parameters.

func (*Plugin) SetMainSessionCookie

func (p *Plugin) SetMainSessionCookie(w http.ResponseWriter, token string, expiresAt time.Time)

SetMainSessionCookie writes the primary signed session cookie to an HTTP response.

func (*Plugin) SetMultiSessionCookie

func (p *Plugin) SetMultiSessionCookie(w http.ResponseWriter, token string, expiresAt time.Time)

SetMultiSessionCookie writes a signed multi-session cookie to an HTTP response.

type Repository

type Repository interface {
	// GetSessionByToken retrieves a session entity by its unique session token string.
	//
	// Function:
	//   Used during session validation and active device count evaluation.
	//
	// Storage:
	//   Database (GORM / SQL) - Query sessions table by token column index.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - token: Session token string.
	//
	// Returns:
	//   - *entity.Session: Matching session entity if found.
	//   - error: Nil on success, or database error.
	//
	// Example SQL:
	//   SELECT id, user_id, token, expires_at, created_at, updated_at FROM sessions WHERE token = $1 LIMIT 1;
	GetSessionByToken(ctx context.Context, token string) (*entity.Session, error)

	// GetUserByID retrieves a user entity by its unique user ID.
	//
	// Function:
	//   Used to resolve user details linked to active multi-session tokens.
	//
	// Storage:
	//   Database (GORM / SQL) - Primary key lookup on users table.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - id: Unique user primary key ID.
	//
	// Returns:
	//   - *entity.User: Matching user entity if found.
	//   - error: Nil on success, or database error.
	//
	// Example SQL:
	//   SELECT id, email, name, avatar, role, created_at, updated_at FROM users WHERE id = $1 LIMIT 1;
	GetUserByID(ctx context.Context, id string) (*entity.User, error)

	// DeleteSession removes a single session by token string.
	//
	// Function:
	//   Called during individual session revocation or logout.
	//
	// Storage:
	//   Database (GORM / SQL) - Delete row matching token.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - token: Target session token string to revoke.
	//
	// Returns:
	//   - error: Nil on success, or database error.
	//
	// Example SQL:
	//   DELETE FROM sessions WHERE token = $1;
	DeleteSession(ctx context.Context, token string) error

	// DeleteSessions removes multiple sessions by token strings.
	//
	// Function:
	//   Called during mass revocation or session limit enforcement.
	//
	// Storage:
	//   Database (GORM / SQL) - Batch delete rows where token IN ($1, $2, ...).
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - tokens: Slice of session token strings to revoke.
	//
	// Returns:
	//   - error: Nil on success, or database error.
	//
	// Example SQL:
	//   DELETE FROM sessions WHERE token IN ($1, $2, $3);
	DeleteSessions(ctx context.Context, tokens []string) error

	// FindSessionsByTokens returns all valid sessions and corresponding users for a given slice of session tokens.
	//
	// Function:
	//   Called during multi-session cookie evaluation to list all active accounts on a device.
	//
	// Storage:
	//   Database (GORM / SQL) - Join sessions and users where token IN ($1, $2, ...).
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - tokens: Slice of multi-session token strings.
	//
	// Returns:
	//   - []*entity.Session: List of active session entities.
	//   - []*entity.User: List of corresponding user entities.
	//   - error: Nil on success, or database error.
	//
	// Example SQL:
	//   SELECT s.id, s.user_id, s.token, s.expires_at, u.email, u.name FROM sessions s JOIN users u ON s.user_id = u.id WHERE s.token IN ($1, $2);
	FindSessionsByTokens(ctx context.Context, tokens []string) ([]*entity.Session, []*entity.User, error)
}

Repository defines data access contract required by the MultiSession plugin. Implement this interface on your custom database adapter (e.g. PostgreSQL, MySQL, SQLite, GORM).

Implementation Example (GORM / database/sql):

type GormMultiSessionRepository struct {
	db *gorm.DB
}

func (r *GormMultiSessionRepository) GetSessionByToken(ctx context.Context, token string) (*entity.Session, error) {
	var s entity.Session
	if err := r.db.WithContext(ctx).Where("token = ?", token).First(&s).Error; err != nil {
		return nil, err
	}
	return &s, nil
}

type RevokeAllSessionsParams

type RevokeAllSessionsParams struct {
	// DeviceTokens specifies all verified multi-session tokens present on the device.
	DeviceTokens []string `json:"deviceTokens"`
}

RevokeAllSessionsParams contains input parameters for revoking all sessions on a device.

type RevokeAllSessionsResult

type RevokeAllSessionsResult struct {
	// Status indicates if the revocation succeeded.
	Status bool `json:"status"`

	// RevokedTokens is the list of all tokens removed from the database.
	RevokedTokens []string `json:"revokedTokens"`

	// Count is the number of sessions revoked.
	Count int `json:"count"`
}

RevokeAllSessionsResult contains the output data after revoking all sessions on a device.

type RevokeDeviceSessionEventPayload

type RevokeDeviceSessionEventPayload struct {
	Params *RevokeDeviceSessionParams
	Result *RevokeDeviceSessionResult
	Extra  map[string]any
}

RevokeDeviceSessionEventPayload contains parameter and result data associated with session revocation lifecycle events.

type RevokeDeviceSessionParams

type RevokeDeviceSessionParams struct {
	// SessionToken specifies the target session token to revoke.
	SessionToken string `json:"sessionToken,omitempty"`

	// RevokeAll if true indicates all device sessions should be revoked.
	RevokeAll bool `json:"revokeAll,omitempty"`

	// RevokeOther if true indicates all device sessions EXCEPT the active session should be revoked.
	RevokeOther bool `json:"revokeOther,omitempty"`

	// DeviceTokens specifies the list of all multi-session tokens registered on the device.
	DeviceTokens []string `json:"deviceTokens,omitempty"`

	// ActiveTokenInReq specifies the token of the session currently marked as active in the request.
	ActiveTokenInReq string `json:"activeTokenInReq,omitempty"`
}

RevokeDeviceSessionParams contains input parameters for revoking a single session, all sessions, or all other sessions.

type RevokeDeviceSessionResult

type RevokeDeviceSessionResult struct {
	// Status indicates if the revocation operation succeeded.
	Status bool `json:"status"`

	// RevokedToken contains the single token revoked (if single session revocation).
	RevokedToken string `json:"revokedToken,omitempty"`

	// RevokedTokens contains the list of all tokens revoked during mass/other revocation.
	RevokedTokens []string `json:"revokedTokens,omitempty"`

	// WasActive indicates whether the revoked session was the currently active session.
	WasActive bool `json:"wasActive"`

	// NewActiveSession points to the next available session to set as active, if applicable.
	NewActiveSession *entity.Session `json:"newActiveSession,omitempty"`

	// ClearActiveSession indicates whether the primary session cookie should be cleared.
	ClearActiveSession bool `json:"clearActiveSession,omitempty"`
}

RevokeDeviceSessionResult contains the output data after revoking one or more device sessions.

type RevokeOtherSessionsParams

type RevokeOtherSessionsParams struct {
	// DeviceTokens specifies all verified multi-session tokens present on the device.
	DeviceTokens []string `json:"deviceTokens"`

	// ActiveToken specifies the token of the currently active session to keep.
	ActiveToken string `json:"activeToken"`
}

RevokeOtherSessionsParams contains input parameters for revoking all device sessions EXCEPT the active session.

type RevokeOtherSessionsResult

type RevokeOtherSessionsResult struct {
	// Status indicates if the revocation succeeded.
	Status bool `json:"status"`

	// RevokedTokens is the list of non-active tokens removed from the database.
	RevokedTokens []string `json:"revokedTokens"`

	// Count is the number of non-active sessions revoked.
	Count int `json:"count"`
}

RevokeOtherSessionsResult contains the output data after revoking all other sessions.

type SessionActivatedCallback

type SessionActivatedCallback func(ctx context.Context, res *SetActiveSessionResult) error

SessionActivatedCallback is invoked whenever a device session is set active.

type SessionCreatedEventPayload

type SessionCreatedEventPayload struct {
	Session *entity.Session
	Extra   map[string]any
}

SessionCreatedEventPayload contains entity data associated with multi-session creation events.

type SessionRevokedCallback

type SessionRevokedCallback func(ctx context.Context, res *RevokeDeviceSessionResult) error

SessionRevokedCallback is invoked whenever a device session is revoked.

type SetActiveSessionEventPayload

type SetActiveSessionEventPayload struct {
	Params *SetActiveSessionParams
	Result *SetActiveSessionResult
	Extra  map[string]any
}

SetActiveSessionEventPayload contains parameter and result data associated with session activation lifecycle events.

type SetActiveSessionParams

type SetActiveSessionParams struct {
	// SessionToken specifies the target session token to set as active.
	SessionToken string `json:"sessionToken"`
}

SetActiveSessionParams contains input parameters for establishing an active device session.

type SetActiveSessionResult

type SetActiveSessionResult struct {
	// DeviceSession holds the newly activated session and user details.
	DeviceSession DeviceSession `json:"deviceSession"`

	// ActiveToken holds the verified token string of the active session.
	ActiveToken string `json:"activeToken"`

	// ExpiresAt specifies when the active session expires.
	ExpiresAt time.Time `json:"expiresAt"`

	// Status indicates if the activation operation succeeded.
	Status bool `json:"status"`
}

SetActiveSessionResult contains the output data after activating a session.

type SignOutEventPayload

type SignOutEventPayload struct {
	RevokedTokens []string
	Extra         map[string]any
}

SignOutEventPayload contains revoked token data associated with mass sign-out events.

type StatusResponse

type StatusResponse struct {
	Status bool `json:"status"`
}

StatusResponse represents a simple boolean status response payload.

Jump to

Keyboard shortcuts

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