gorm

package
v0.0.26 Latest Latest
Warning

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

Go to latest
Published: Jan 20, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

Documentation

Overview

Package gorm provides GORM-based implementations of oneauth store interfaces. It supports any database that GORM supports (PostgreSQL, MySQL, SQLite, etc.) and is suitable for production deployments requiring relational database storage.

Database Schema

The package auto-migrates the following tables:

  • users: User accounts
  • identities: Email/phone identities linked to users
  • channels: Authentication channels (local, google, github, etc.)
  • auth_tokens: Verification and password reset tokens
  • refresh_tokens: Long-lived refresh tokens for API access
  • api_keys: Long-lived API keys for programmatic access

Usage

db, _ := gorm.Open(postgres.Open(dsn), &gorm.Config{})
userStore := gormstore.NewUserStore(db)
refreshTokenStore := gormstore.NewRefreshTokenStore(db)
apiKeyStore := gormstore.NewAPIKeyStore(db)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AutoMigrate

func AutoMigrate(db *gorm.DB) error

AutoMigrate runs database migrations for all oneauth tables

Types

type APIKeyModel

type APIKeyModel struct {
	KeyID      string      `gorm:"primaryKey;size:64"`
	KeyHash    string      `gorm:"size:128"`
	UserID     string      `gorm:"size:64;index"`
	Name       string      `gorm:"size:255"`
	Scopes     StringSlice `gorm:"type:jsonb"`
	CreatedAt  time.Time   `gorm:"autoCreateTime"`
	ExpiresAt  *time.Time
	LastUsedAt time.Time
	RevokedAt  *time.Time
	Revoked    bool `gorm:"default:false;index"`
}

APIKeyModel is the GORM model for API keys

func APIKeyToModel

func APIKeyToModel(k *oa.APIKey) *APIKeyModel

func (APIKeyModel) TableName

func (APIKeyModel) TableName() string

func (*APIKeyModel) ToAPIKey

func (m *APIKeyModel) ToAPIKey() *oa.APIKey

type APIKeyStore

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

APIKeyStore implements oa.APIKeyStore using GORM

func NewAPIKeyStore

func NewAPIKeyStore(db *gorm.DB) *APIKeyStore

func (*APIKeyStore) CreateAPIKey

func (s *APIKeyStore) CreateAPIKey(userID, name string, scopes []string, expiresAt *time.Time) (string, *oa.APIKey, error)

func (*APIKeyStore) GetAPIKeyByID

func (s *APIKeyStore) GetAPIKeyByID(keyID string) (*oa.APIKey, error)

func (*APIKeyStore) ListUserAPIKeys

func (s *APIKeyStore) ListUserAPIKeys(userID string) ([]*oa.APIKey, error)

func (*APIKeyStore) RevokeAPIKey

func (s *APIKeyStore) RevokeAPIKey(keyID string) error

func (*APIKeyStore) UpdateAPIKeyLastUsed

func (s *APIKeyStore) UpdateAPIKeyLastUsed(keyID string) error

func (*APIKeyStore) ValidateAPIKey

func (s *APIKeyStore) ValidateAPIKey(fullKey string) (*oa.APIKey, error)

type AuthTokenModel

type AuthTokenModel struct {
	Token     string       `gorm:"primaryKey;size:128"`
	Type      oa.TokenType `gorm:"size:32;index"`
	UserID    string       `gorm:"size:64;index"`
	Email     string       `gorm:"size:255"`
	CreatedAt time.Time    `gorm:"autoCreateTime"`
	ExpiresAt time.Time    `gorm:"index"`
}

AuthTokenModel is the GORM model for verification/reset tokens

func AuthTokenToModel

func AuthTokenToModel(t *oa.AuthToken) *AuthTokenModel

func (AuthTokenModel) TableName

func (AuthTokenModel) TableName() string

func (*AuthTokenModel) ToAuthToken

func (m *AuthTokenModel) ToAuthToken() *oa.AuthToken

type ChannelModel

type ChannelModel struct {
	Provider    string    `gorm:"primaryKey;size:32"`
	IdentityKey string    `gorm:"primaryKey;size:320"`
	Credentials JSONMap   `gorm:"type:jsonb"`
	Profile     JSONMap   `gorm:"type:jsonb"`
	CreatedAt   time.Time `gorm:"autoCreateTime"`
	UpdatedAt   time.Time `gorm:"autoUpdateTime"`
}

ChannelModel is the GORM model for authentication channels

func ChannelToModel

func ChannelToModel(c *oa.Channel) *ChannelModel

func (ChannelModel) TableName

func (ChannelModel) TableName() string

func (*ChannelModel) ToChannel

func (m *ChannelModel) ToChannel() *oa.Channel

type ChannelStore

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

ChannelStore implements oa.ChannelStore using GORM

func NewChannelStore

func NewChannelStore(db *gorm.DB) *ChannelStore

func (*ChannelStore) GetChannel

func (s *ChannelStore) GetChannel(provider string, identityKey string, createIfMissing bool) (*oa.Channel, bool, error)

func (*ChannelStore) GetChannelsByIdentity

func (s *ChannelStore) GetChannelsByIdentity(identityKey string) ([]*oa.Channel, error)

func (*ChannelStore) SaveChannel

func (s *ChannelStore) SaveChannel(channel *oa.Channel) error

type GORMUser

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

GORMUser implements the oa.User interface

func (*GORMUser) Id

func (u *GORMUser) Id() string

func (*GORMUser) Profile

func (u *GORMUser) Profile() map[string]any

type IdentityModel

type IdentityModel struct {
	Type      string    `gorm:"primaryKey;size:32"`
	Value     string    `gorm:"primaryKey;size:255"`
	UserID    string    `gorm:"size:64;index"`
	Verified  bool      `gorm:"default:false"`
	CreatedAt time.Time `gorm:"autoCreateTime"`
}

IdentityModel is the GORM model for identities

func IdentityToModel

func IdentityToModel(i *oa.Identity) *IdentityModel

func (IdentityModel) TableName

func (IdentityModel) TableName() string

func (*IdentityModel) ToIdentity

func (m *IdentityModel) ToIdentity() *oa.Identity

type IdentityStore

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

IdentityStore implements oa.IdentityStore using GORM

func NewIdentityStore

func NewIdentityStore(db *gorm.DB) *IdentityStore

func (*IdentityStore) GetIdentity

func (s *IdentityStore) GetIdentity(identityType, identityValue string, createIfMissing bool) (*oa.Identity, bool, error)

func (*IdentityStore) GetUserIdentities

func (s *IdentityStore) GetUserIdentities(userId string) ([]*oa.Identity, error)

func (*IdentityStore) MarkIdentityVerified

func (s *IdentityStore) MarkIdentityVerified(identityType, identityValue string) error

func (*IdentityStore) SaveIdentity

func (s *IdentityStore) SaveIdentity(identity *oa.Identity) error

func (*IdentityStore) SetUserForIdentity

func (s *IdentityStore) SetUserForIdentity(identityType, identityValue string, newUserId string) error

type JSONMap

type JSONMap map[string]any

JSONMap is a helper type for storing JSON maps in GORM

func (*JSONMap) Scan

func (m *JSONMap) Scan(value any) error

func (JSONMap) Value

func (m JSONMap) Value() (driver.Value, error)

type RefreshTokenModel

type RefreshTokenModel struct {
	TokenHash  string      `gorm:"primaryKey;size:64"`
	Token      string      `gorm:"-"` // Not stored, only used in memory
	UserID     string      `gorm:"size:64;index"`
	ClientID   string      `gorm:"size:64"`
	DeviceInfo JSONMap     `gorm:"type:jsonb"`
	Family     string      `gorm:"size:32;index"`
	Generation int         `gorm:"default:1"`
	Scopes     StringSlice `gorm:"type:jsonb"`
	CreatedAt  time.Time   `gorm:"autoCreateTime"`
	ExpiresAt  time.Time   `gorm:"index"`
	LastUsedAt time.Time
	RevokedAt  *time.Time
	Revoked    bool `gorm:"default:false;index"`
}

RefreshTokenModel is the GORM model for refresh tokens

func RefreshTokenToModel

func RefreshTokenToModel(t *oa.RefreshToken) *RefreshTokenModel

func (RefreshTokenModel) TableName

func (RefreshTokenModel) TableName() string

func (*RefreshTokenModel) ToRefreshToken

func (m *RefreshTokenModel) ToRefreshToken() *oa.RefreshToken

type RefreshTokenStore

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

RefreshTokenStore implements oa.RefreshTokenStore using GORM

func NewRefreshTokenStore

func NewRefreshTokenStore(db *gorm.DB) *RefreshTokenStore

func (*RefreshTokenStore) CleanupExpiredTokens

func (s *RefreshTokenStore) CleanupExpiredTokens() error

func (*RefreshTokenStore) CreateRefreshToken

func (s *RefreshTokenStore) CreateRefreshToken(userID, clientID string, deviceInfo map[string]any, scopes []string) (*oa.RefreshToken, error)

func (*RefreshTokenStore) GetRefreshToken

func (s *RefreshTokenStore) GetRefreshToken(token string) (*oa.RefreshToken, error)

func (*RefreshTokenStore) GetUserTokens

func (s *RefreshTokenStore) GetUserTokens(userID string) ([]*oa.RefreshToken, error)

func (*RefreshTokenStore) RevokeRefreshToken

func (s *RefreshTokenStore) RevokeRefreshToken(token string) error

func (*RefreshTokenStore) RevokeTokenFamily

func (s *RefreshTokenStore) RevokeTokenFamily(family string) error

func (*RefreshTokenStore) RevokeUserTokens

func (s *RefreshTokenStore) RevokeUserTokens(userID string) error

func (*RefreshTokenStore) RotateRefreshToken

func (s *RefreshTokenStore) RotateRefreshToken(oldToken string) (*oa.RefreshToken, error)

type StringSlice

type StringSlice []string

StringSlice is a helper type for storing string slices in GORM

func (*StringSlice) Scan

func (s *StringSlice) Scan(value any) error

func (StringSlice) Value

func (s StringSlice) Value() (driver.Value, error)

type TokenStore

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

TokenStore implements oa.TokenStore using GORM

func NewTokenStore

func NewTokenStore(db *gorm.DB) *TokenStore

func (*TokenStore) CreateToken

func (s *TokenStore) CreateToken(userID, email string, tokenType oa.TokenType, expiryDuration time.Duration) (*oa.AuthToken, error)

func (*TokenStore) DeleteToken

func (s *TokenStore) DeleteToken(token string) error

func (*TokenStore) DeleteUserTokens

func (s *TokenStore) DeleteUserTokens(userID string, tokenType oa.TokenType) error

func (*TokenStore) GetToken

func (s *TokenStore) GetToken(token string) (*oa.AuthToken, error)

type UserModel

type UserModel struct {
	ID        string    `gorm:"primaryKey;size:64"`
	IsActive  bool      `gorm:"default:true"`
	Profile   JSONMap   `gorm:"type:jsonb"`
	CreatedAt time.Time `gorm:"autoCreateTime"`
	UpdatedAt time.Time `gorm:"autoUpdateTime"`
}

UserModel is the GORM model for users

func (UserModel) TableName

func (UserModel) TableName() string

type UserStore

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

UserStore implements oa.UserStore using GORM

func NewUserStore

func NewUserStore(db *gorm.DB) *UserStore

func (*UserStore) CreateUser

func (s *UserStore) CreateUser(userId string, isActive bool, profile map[string]any) (oa.User, error)

func (*UserStore) GetUserById

func (s *UserStore) GetUserById(userId string) (oa.User, error)

func (*UserStore) SaveUser

func (s *UserStore) SaveUser(user oa.User) error

type UsernameModel added in v0.0.26

type UsernameModel struct {
	// NormalizedUsername is the lowercase version (primary key for case-insensitive lookup)
	NormalizedUsername string    `gorm:"primaryKey;size:64"`
	Username           string    `gorm:"size:64;not null"` // Original case-preserved
	UserID             string    `gorm:"size:64;index;not null"`
	Version            int       `gorm:"default:1"` // For optimistic concurrency control
	CreatedAt          time.Time `gorm:"autoCreateTime"`
	UpdatedAt          time.Time `gorm:"autoUpdateTime"`
}

UsernameModel is the GORM model for username -> userID mapping Used for enforcing username uniqueness and enabling username-based login

func (UsernameModel) TableName added in v0.0.26

func (UsernameModel) TableName() string

type UsernameStore added in v0.0.26

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

UsernameStore implements oa.UsernameStore using GORM with optimistic concurrency.

Purpose

Provides username uniqueness enforcement and username-based login lookup. This is optional - only configure it if your app needs:

  • Username uniqueness (prevent two users from having same username)
  • Username-based login (login with "johndoe" instead of email)

Concurrency Model

Uses optimistic locking with version numbers. Updates use "WHERE version = ?" clauses to detect concurrent modifications. If a conflict occurs, the operation returns an error and can be retried.

Setup

db, _ := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
gorm.AutoMigrate(db) // Creates usernames table
usernameStore := gorm.NewUsernameStore(db)

// Use with LocalAuth
localAuth := &oneauth.LocalAuth{
    UsernameStore: usernameStore,
    SignupPolicy: &oneauth.SignupPolicy{
        RequireUsername:       true,
        EnforceUsernameUnique: true,
    },
}

func NewUsernameStore added in v0.0.26

func NewUsernameStore(db *gorm.DB) *UsernameStore

NewUsernameStore creates a new GORM-backed UsernameStore

func (*UsernameStore) ChangeUsername added in v0.0.26

func (s *UsernameStore) ChangeUsername(oldUsername, newUsername, userID string) error

ChangeUsername atomically changes a username using optimistic concurrency. Returns error if new username is already taken or concurrent modification detected.

Usage

Called from a "Change Username" profile page handler.

Concurrency

Uses version check to detect concurrent modifications. If another process modifies the username between read and update, returns error for retry.

func (*UsernameStore) GetUserByUsername added in v0.0.26

func (s *UsernameStore) GetUserByUsername(username string) (string, error)

GetUserByUsername looks up a userID by username (case-insensitive).

Usage

Called by NewCredentialsValidatorWithUsername during login when user enters a username instead of email.

func (*UsernameStore) ReleaseUsername added in v0.0.26

func (s *UsernameStore) ReleaseUsername(username string) error

ReleaseUsername removes a username reservation.

When to Use

Call this when:

  • User deletes their account
  • Admin removes a username (e.g., for policy violations)

func (*UsernameStore) ReserveUsername added in v0.0.26

func (s *UsernameStore) ReserveUsername(username string, userID string) error

ReserveUsername reserves a username for a user. Returns error if username is already taken by a different user.

Concurrency

Uses database unique constraint on primary key. Concurrent inserts for the same username will have one succeed and one fail with a constraint violation.

Jump to

Keyboard shortcuts

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