auth

package
v0.3.88 Latest Latest
Warning

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

Go to latest
Published: Oct 30, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package auth implements authentication for the Klever Node Hub dashboard.

DEPENDENCY NOTE: This package uses github.com/go-webauthn/webauthn as the sole exception to the stdlib-only rule. WebAuthn/FIDO2 requires CBOR parsing, attestation verification, and compliance with W3C WebAuthn spec — implementing this manually would be error-prone and a security risk. The go-webauthn library is the standard Go implementation, actively maintained, and widely audited. All other auth components (JWT, recovery codes, middleware) use stdlib only.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNoKleverAddress  = errors.New("no klever admin address configured")
	ErrInvalidAddress   = errors.New("invalid klever address format")
	ErrChallengeExpired = errors.New("challenge expired or not found")
	ErrAddressMismatch  = errors.New("address does not match registered admin")
	ErrInvalidSignature = errors.New("invalid signature")
)
View Source
var ErrPasswordTooShort = errors.New("password must be at least 8 characters")

ErrPasswordTooShort is returned when the password is shorter than the minimum length.

Functions

func GenerateSigningKey

func GenerateSigningKey() ([]byte, error)

GenerateSigningKey creates a cryptographically random 32-byte signing key.

func HashArgon2id

func HashArgon2id(input string) (string, error)

HashArgon2id hashes the input with Argon2id and returns hex(salt + hash).

func Middleware

func Middleware(jm *JWTManager) func(http.Handler) http.Handler

Middleware creates an HTTP middleware that validates JWT tokens. Tokens are read from the "Authorization: Bearer <token>" header or from an httpOnly cookie named "access_token".

func VerifyArgon2id

func VerifyArgon2id(input, storedHash string) bool

VerifyArgon2id checks an input against a stored Argon2id hash. Uses constant-time comparison to prevent timing attacks.

Types

type JWTClaims

type JWTClaims struct {
	Subject   string `json:"sub"`
	IssuedAt  int64  `json:"iat"`
	ExpiresAt int64  `json:"exp"`
	TokenType string `json:"type"` // "access" or "refresh"
}

JWTClaims holds the JWT payload.

func ClaimsFromContext

func ClaimsFromContext(ctx context.Context) *JWTClaims

ClaimsFromContext extracts JWT claims from the request context. Returns nil if no claims are present.

type JWTManager

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

JWTManager handles JWT token creation and validation.

func NewJWTManager

func NewJWTManager(signingKey []byte) (*JWTManager, error)

NewJWTManager creates a new JWTManager with the given signing key. Key must be at least 32 bytes.

func (*JWTManager) IssueTokenPair

func (jm *JWTManager) IssueTokenPair(subject string) (*TokenPair, error)

IssueTokenPair creates a new access + refresh token pair.

func (*JWTManager) RefreshTokenPair

func (jm *JWTManager) RefreshTokenPair(refreshToken string) (*TokenPair, error)

RefreshTokenPair validates a refresh token and issues a new token pair.

func (*JWTManager) ValidateAccessToken

func (jm *JWTManager) ValidateAccessToken(token string) (*JWTClaims, error)

ValidateAccessToken validates an access token and returns its claims.

func (*JWTManager) ValidateRefreshToken

func (jm *JWTManager) ValidateRefreshToken(token string) (*JWTClaims, error)

ValidateRefreshToken validates a refresh token and returns its claims.

type KleverAuthManager

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

KleverAuthManager handles Klever Extension wallet authentication. It stores a single admin klv1... address and manages challenge-response sessions.

func NewKleverAuthManager

func NewKleverAuthManager(storedAddress string) *KleverAuthManager

NewKleverAuthManager creates a new KleverAuthManager with an optional stored address.

func (*KleverAuthManager) Address

func (k *KleverAuthManager) Address() string

Address returns the registered admin address.

func (*KleverAuthManager) CreateChallenge

func (k *KleverAuthManager) CreateChallenge(address string) (string, error)

CreateChallenge generates a random nonce for the given address. Returns the hex-encoded nonce.

func (*KleverAuthManager) CreateSetupChallenge

func (k *KleverAuthManager) CreateSetupChallenge(address string) (string, error)

CreateSetupChallenge generates a nonce for any valid klv1... address (no registered address required). Used during wallet linking in settings to prove ownership before saving.

func (*KleverAuthManager) HasAddress

func (k *KleverAuthManager) HasAddress() bool

HasAddress returns whether an admin address is configured.

func (*KleverAuthManager) RemoveAddress

func (k *KleverAuthManager) RemoveAddress()

RemoveAddress removes the registered admin address.

func (*KleverAuthManager) SetAddress

func (k *KleverAuthManager) SetAddress(address string) error

SetAddress registers a klv1... address as the admin wallet.

func (*KleverAuthManager) VerifySetupSignature

func (k *KleverAuthManager) VerifySetupSignature(address, nonce, signature string) error

VerifySetupSignature verifies a signature for wallet linking (no registered address check). On success, the caller should save the address.

func (*KleverAuthManager) VerifySignature

func (k *KleverAuthManager) VerifySignature(address, nonce, signature string) error

VerifySignature verifies an Ed25519 signature from the Klever Extension. The signature should be hex-encoded (128 hex chars = 64 bytes).

type PasskeyCredential

type PasskeyCredential struct {
	ID             string `json:"id"`              // Credential ID (hex-encoded)
	PublicKey      []byte `json:"public_key"`      // COSE public key
	Name           string `json:"name"`            // User-friendly name (e.g., "MacBook Pro")
	SignCount      uint32 `json:"sign_count"`      // Signature counter (replay detection)
	BackupEligible bool   `json:"backup_eligible"` // Whether credential supports backup/sync
	BackupState    bool   `json:"backup_state"`    // Whether credential is currently backed up
	RegisteredAt   int64  `json:"registered_at"`   // Unix timestamp
}

PasskeyCredential stores a registered WebAuthn credential.

type PasswordManager

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

PasswordManager handles password-based authentication with Argon2id hashing.

func NewPasswordManager

func NewPasswordManager(storedHash string) *PasswordManager

NewPasswordManager creates a new PasswordManager with an optional stored hash.

func (*PasswordManager) HasPassword

func (pm *PasswordManager) HasPassword() bool

HasPassword returns true if a password has been set.

func (*PasswordManager) Hash

func (pm *PasswordManager) Hash() string

Hash returns the current hash for persistence.

func (*PasswordManager) SetPassword

func (pm *PasswordManager) SetPassword(password string) (string, error)

SetPassword hashes and stores a new password. Returns the hash for persistence.

func (*PasswordManager) Verify

func (pm *PasswordManager) Verify(password string) bool

Verify checks a password against the stored hash.

type RateLimiter

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

RateLimiter tracks failed login attempts per IP with a sliding window.

func NewRateLimiter

func NewRateLimiter(window time.Duration, maxFails int) *RateLimiter

NewRateLimiter creates a rate limiter with the given window and max failures.

func (*RateLimiter) Allow

func (rl *RateLimiter) Allow(ip string) bool

Allow checks if an IP is allowed to attempt a login.

func (*RateLimiter) RecordFailure

func (rl *RateLimiter) RecordFailure(ip string)

RecordFailure records a failed login attempt for the given IP.

func (*RateLimiter) Reset

func (rl *RateLimiter) Reset(ip string)

Reset clears the failure count for an IP after a successful login.

type RecoveryCode

type RecoveryCode struct {
	Hash string `json:"hash"` // Argon2id hash (hex-encoded: salt + hash)
	Used bool   `json:"used"`
}

RecoveryCode holds a hashed recovery code with its usage state.

type RecoveryManager

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

RecoveryManager handles generation, hashing, and verification of recovery codes.

func NewRecoveryManager

func NewRecoveryManager(codes []RecoveryCode) *RecoveryManager

NewRecoveryManager creates a new RecoveryManager with the given stored codes.

func (*RecoveryManager) Codes

func (rm *RecoveryManager) Codes() []RecoveryCode

Codes returns the current stored codes (for persistence).

func (*RecoveryManager) GenerateCodes

func (rm *RecoveryManager) GenerateCodes() (plaintextCodes []string, hashedCodes []RecoveryCode, err error)

GenerateCodes generates a new set of recovery codes. Returns the plaintext codes (to show the user once) and the hashed codes (to store).

func (*RecoveryManager) Remaining

func (rm *RecoveryManager) Remaining() int

Remaining returns the number of unused recovery codes.

func (*RecoveryManager) Verify

func (rm *RecoveryManager) Verify(code string) bool

Verify checks a recovery code against stored hashes. If valid, the code is marked as used and cannot be reused. Returns true if the code was valid and unused.

type TokenPair

type TokenPair struct {
	AccessToken  string `json:"access_token"`
	RefreshToken string `json:"refresh_token"`
	ExpiresIn    int64  `json:"expires_in"` // seconds
}

TokenPair holds an access token and refresh token.

type WebAuthnConfig

type WebAuthnConfig struct {
	RPDisplayName string   // Relying Party display name (e.g., "Klever Node Hub")
	RPID          string   // Relying Party ID (e.g., "localhost" or domain)
	RPOrigins     []string // Allowed origins (e.g., "https://localhost:9443")
	InstanceID    string   // Unique ID for this dashboard instance (prevents passkey collisions when multiple dashboards share the same RP ID)
}

WebAuthnConfig holds configuration for WebAuthn initialization.

type WebAuthnManager

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

WebAuthnManager handles passkey registration and authentication.

func NewWebAuthnManager

func NewWebAuthnManager(config WebAuthnConfig, credentials []PasskeyCredential) (*WebAuthnManager, error)

NewWebAuthnManager creates a new WebAuthn manager.

func (*WebAuthnManager) BeginLogin

BeginLogin starts a passkey authentication ceremony.

func (*WebAuthnManager) BeginRegistration

func (wm *WebAuthnManager) BeginRegistration(passkeyName string) (*protocol.CredentialCreation, string, error)

BeginRegistration starts a passkey registration ceremony. Returns the options to send to the browser and a session ID.

func (*WebAuthnManager) CredentialCount

func (wm *WebAuthnManager) CredentialCount() int

CredentialCount returns the number of registered passkeys.

func (*WebAuthnManager) Credentials

func (wm *WebAuthnManager) Credentials() []PasskeyCredential

Credentials returns the current stored credentials (for persistence).

func (*WebAuthnManager) DeletePasskey

func (wm *WebAuthnManager) DeletePasskey(id string) error

DeletePasskey removes a passkey by ID. Enforces minimum 1 passkey.

func (*WebAuthnManager) FinishLogin

func (wm *WebAuthnManager) FinishLogin(sessionID string, response *protocol.ParsedCredentialAssertionData) error

FinishLogin completes a passkey authentication ceremony.

func (*WebAuthnManager) FinishRegistration

func (wm *WebAuthnManager) FinishRegistration(sessionID string, response *protocol.ParsedCredentialCreationData, name string) error

FinishRegistration completes a passkey registration ceremony.

func (*WebAuthnManager) HasCredentials

func (wm *WebAuthnManager) HasCredentials() bool

HasCredentials returns true if at least one passkey is registered.

Jump to

Keyboard shortcuts

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