keyring

package module
v0.0.0-...-33f1716 Latest Latest
Warning

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

Go to latest
Published: Jul 1, 2026 License: MIT Imports: 22 Imported by: 0

README

Keyring

Maintained fork CI Go Reference

Keyring provides a context-aware provider API for secure credential storage services.

Maintained fork status

This repository is a permanent, maintained fork of 99designs/keyring. The upstream project appears to be abandoned; its maintenance status has been asked about upstream, but the project remains without active stewardship there.

I originally authored Keyring at 99designs. I'm sad to see the upstream project left unmaintained, so I maintain this fork for ongoing fixes, dependency updates, and platform support. The Go module path for this fork is github.com/lox/keyring.

This fork has intentionally diverged from upstream. It uses a different module path and a context-aware provider API in the root package, so it is not a drop-in replacement for github.com/99designs/keyring.

This is not the only maintained continuation of the project. ByteNess/keyring is also a maintained fork, with its own feature set and maintenance choices.

Currently Keyring supports the following backends

Code map

The main paths are:

  • keyring.go - public Open, Keyring, Provider, backend order, fallback, and stable errors
  • providers.go - built-in provider constructors such as FileProvider, KeychainProvider, and PassProvider
  • file.go - encrypted file backend storage, portable filenames, and legacy filename reads/removes
  • adapter.go - adapter from the older backend implementations to the context-aware root API
  • docs/api.md - migration notes and provider examples

Usage

The short version of how to use keyring is shown below.

ctx := context.Background()

ring, _ := keyring.Open(ctx, keyring.WithServiceName("example"))

_ = ring.Set(ctx, keyring.Item{
	Key: "foo",
	Data: []byte("secret-bar"),
})

i, _ := ring.Get(ctx, "foo")

fmt.Printf("%s", i.Data)

For more detail on the API please check the keyring package docs

Provider API

The root package keeps the built-in desktop backends in this repository while making backend selection extensible through explicit provider values and OptionFunc configuration.

ctx := context.Background()

ring, err := keyring.Open(ctx,
	keyring.WithServiceName("example"),
	keyring.WithBackends(keyring.KeychainBackend, keyring.FileBackend),
	keyring.WithProvider(keyring.FileProvider(
		keyring.FileDir("/path/to/keyring"),
		keyring.FilePrompt(keyring.FixedStringPrompt("passphrase")),
	)),
)
if err != nil {
	log.Fatal(err)
}

_ = ring.Set(ctx, keyring.Item{
	Key:  "foo",
	Data: []byte("secret-bar"),
})

External providers, such as a future 1Password provider, can live in separate modules without adding their dependencies to the core package:

ring, err := keyring.Open(ctx,
	keyring.WithServiceName("example"),
	keyring.WithBackends(onepassword.Backend, keyring.KeychainBackend, keyring.FileBackend),
	keyring.WithProvider(onepassword.Provider(
		onepassword.WithVault("Private"),
	)),
)

See docs/api.md and the package examples for more detail.

Encrypted file backend

The file backend is built into this repository. Use it for headless, container, or agent environments where an OS keychain is unavailable or too interactive:

ring, err := keyring.Open(ctx,
	keyring.WithServiceName("example"),
	keyring.WithBackends(keyring.FileBackend),
	keyring.WithProvider(keyring.FileProvider(
		keyring.FileDir("/path/to/keyring"),
		keyring.FilePrompt(keyring.FixedStringPrompt(passphrase)),
	)),
)

The backend stores one encrypted file per item under an internal directory in FileDir. Filenames are encoded so application keys containing characters such as /, :, <, >, ?, or * remain portable across platforms. Existing root-level files written by older versions are still read, listed, and removed through the legacy filename path.

Applications still own their runtime policy: where the directory lives, how the passphrase is supplied, whether to force the file backend in headless mode, and whether to add app-level locking or timeouts. The provider API lets applications wrap FileProvider for those policies without reimplementing encrypted file storage; provider_test.go includes a small wrapper example.

Testing

Most tests run with only Go:

go test ./...
go test -race ./...
go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.12.2 run
go run golang.org/x/vuln/cmd/govulncheck@latest ./...

The pass integration tests require pass and gpg; they are skipped when those tools are not installed. Secret Service tests require an interactive DBus-backed desktop session and are skipped in GitHub Actions.

Vagrant can still be used to create linux and windows test environments.

# Start vagrant
vagrant up

# Run go tests on all platforms
./bin/go-test

Contributing

Contributions to this fork of the keyring package are most welcome from engineers of all backgrounds and skill levels. In particular the addition of extra backends across popular operating systems would be appreciated.

To make a contribution:

  • Fork this repository
  • Make your changes on the fork
  • Submit a pull request back to this repo with a clear description of the problem you're solving
  • Ensure your PR passes all current (and new) tests

...and we'll do our best to get your work merged in

Documentation

Overview

Package keyring provides a context-aware API over desktop credential storage backends.

Index

Examples

Constants

View Source
const (
	KEYCTL_PERM_VIEW    = uint32(1 << 0)
	KEYCTL_PERM_READ    = uint32(1 << 1)
	KEYCTL_PERM_WRITE   = uint32(1 << 2)
	KEYCTL_PERM_SEARCH  = uint32(1 << 3)
	KEYCTL_PERM_LINK    = uint32(1 << 4)
	KEYCTL_PERM_SETATTR = uint32(1 << 5)
	KEYCTL_PERM_ALL     = uint32((1 << 6) - 1)

	KEYCTL_PERM_OTHERS  = 0
	KEYCTL_PERM_GROUP   = 8
	KEYCTL_PERM_USER    = 16
	KEYCTL_PERM_PROCESS = 24
)

Variables

View Source
var (
	ErrUnavailable         = errors.New("keyring backend unavailable")
	ErrNotFound            = errors.New("keyring item not found")
	ErrAccessDenied        = errors.New("keyring access denied")
	ErrTooLarge            = errors.New("credential data exceeds backend limit")
	ErrMetadataUnsupported = errors.New("keyring metadata unsupported")
	ErrMetadataNeedsUnlock = errors.New("keyring metadata requires credentials")
	ErrInvalidOption       = errors.New("invalid keyring option")
	ErrNoProvider          = errors.New("keyring provider not found")
)

Stable errors returned by this package.

View Source
var Debug bool

Debug specifies whether to print debugging output.

View Source
var ErrCredentialTooLarge = ErrTooLarge

ErrCredentialTooLarge is returned when the backend cannot store an item's data because it exceeds that backend's credential size limit.

View Source
var ErrKeyNotFound = ErrNotFound

ErrKeyNotFound is returned when the item is not on the keyring.

View Source
var ErrMetadataNeedsCredentials = ErrMetadataNeedsUnlock

ErrMetadataNeedsCredentials is returned when metadata requires credentials.

View Source
var ErrMetadataNotSupported = ErrMetadataUnsupported

ErrMetadataNotSupported is returned when metadata is not available.

View Source
var ErrNoAvailImpl = ErrUnavailable

ErrNoAvailImpl is returned when a backend cannot be found.

Functions

func ExpandTilde

func ExpandTilde(dir string) (string, error)

ExpandTilde will expand tilde (~/ or ~\ depending on OS) for the user home directory.

func GetKeyringIDForScope

func GetKeyringIDForScope(scope string) (int32, error)

GetKeyringIDForScope get the keyring ID for a given scope.

func GetPermissions

func GetPermissions(process, user, group, others uint32) uint32

GetPermissions constructs the permission mask from the elements.

func TerminalPrompt

func TerminalPrompt(prompt string) (string, error)

TerminalPrompt prompts for a password on stdin without echoing input.

Types

type ArrayKeyring

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

ArrayKeyring is a mock/non-secure backend that meets the Keyring interface. It is intended to be used to aid unit testing of code that relies on the package. NOTE: Do not use in production code.

func NewArrayKeyring

func NewArrayKeyring(initial []Item) *ArrayKeyring

NewArrayKeyring returns an ArrayKeyring, optionally constructed with an initial slice of items.

func (*ArrayKeyring) Get

func (k *ArrayKeyring) Get(ctx context.Context, key string) (Item, error)

Get returns an Item matching key.

func (*ArrayKeyring) Keys

func (k *ArrayKeyring) Keys(ctx context.Context) ([]string, error)

Keys provides a slice of all Item keys on the Keyring.

func (*ArrayKeyring) Metadata

func (k *ArrayKeyring) Metadata(ctx context.Context, _ string) (Metadata, error)

Metadata returns ErrMetadataNeedsUnlock for the in-memory backend.

func (*ArrayKeyring) Remove

func (k *ArrayKeyring) Remove(ctx context.Context, key string) error

Remove deletes an Item from the Keyring.

func (*ArrayKeyring) Set

func (k *ArrayKeyring) Set(ctx context.Context, item Item) error

Set stores an item on the mock Keyring.

type Backend

type Backend string

Backend identifies a credential storage backend.

const (
	InvalidBackend       Backend = ""
	SecretServiceBackend Backend = "secret-service"
	KeychainBackend      Backend = "keychain"
	KeyCtlBackend        Backend = "keyctl"
	KWalletBackend       Backend = "kwallet"
	WinCredBackend       Backend = "wincred"
	FileBackend          Backend = "file"
	PassBackend          Backend = "pass"
)

All currently supported secure storage backends.

func Available

func Available(opts ...Option) ([]Backend, error)

Available returns the available backend names after applying options.

func AvailableBackends

func AvailableBackends() []Backend

AvailableBackends provides a slice of all available backend keys on the current OS.

type BackendType

type BackendType = Backend

BackendType is an alias for Backend for callers migrating from the previous API.

type Config deprecated

type Config struct {
	// AllowedBackends is a whitelist of backend providers that can be used. Nil means all available.
	AllowedBackends []Backend

	// ServiceName is a generic service name that is used by backends that support the concept
	ServiceName string

	// MacOSKeychainNameKeychainName is the name of the macOS keychain that is used
	KeychainName string

	// KeychainTrustApplication is whether the calling application should be trusted by default by items
	KeychainTrustApplication bool

	// KeychainSynchronizable is whether the item can be synchronized to iCloud
	KeychainSynchronizable bool

	// KeychainAccessibleWhenUnlocked is whether the item is accessible when the device is locked
	KeychainAccessibleWhenUnlocked bool

	// KeychainPasswordFunc is an optional function used to prompt the user for a password
	KeychainPasswordFunc PromptFunc

	// FilePasswordFunc is a required function used to prompt the user for a password
	FilePasswordFunc PromptFunc

	// FileDir is the directory that keyring files are stored in, ~/ is resolved to the users' home dir
	FileDir string

	// KeyCtlScope is the scope of the kernel keyring (either "user", "session", "process" or "thread")
	KeyCtlScope string

	// KeyCtlPerm is the permission mask to use for new keys
	KeyCtlPerm uint32

	// KWalletAppID is the application id for KWallet
	KWalletAppID string

	// KWalletFolder is the folder for KWallet
	KWalletFolder string

	// LibSecretCollectionName is the collection name in secret-service. If empty,
	// ServiceName is used. This is the collection path name, which may differ from
	// the display label shown by Secret Service UI tools.
	LibSecretCollectionName string

	// PassDir is the pass password-store directory, ~/ is resolved to the users' home dir
	PassDir string

	// PassCmd is the name of the pass executable
	PassCmd string

	// PassPrefix is a string prefix to prepend to the item path stored in pass
	PassPrefix string

	// WinCredPrefix is a string prefix to prepend to the key name
	WinCredPrefix string
}

Config contains backend-specific configuration used by built-in providers.

Deprecated: use Open with Option values and provider-specific options.

type FallbackPolicy

type FallbackPolicy int

FallbackPolicy controls when Open should try the next provider.

const (
	// FallbackOnUnavailable tries the next provider only when the current
	// provider returns ErrUnavailable.
	FallbackOnUnavailable FallbackPolicy = iota
	// FallbackOnError tries the next provider after any open error.
	FallbackOnError
)

type FileOption

type FileOption func(*fileConfig)

FileOption configures the built-in encrypted file provider.

func FileDir

func FileDir(dir string) FileOption

FileDir sets the encrypted file backend directory.

func FilePrompt

func FilePrompt(prompt PromptFunc) FileOption

FilePrompt sets the encrypted file backend password prompt.

type Item

type Item struct {
	Key         string
	Data        []byte
	Label       string
	Description string

	// Backend specific config.
	KeychainNotTrustApplication bool
	KeychainNotSynchronizable   bool
}

Item is a credential stored in a keyring.

type KWalletOption

type KWalletOption func(*kwalletConfig)

KWalletOption configures the built-in KWallet provider.

func KWalletAppID

func KWalletAppID(appID string) KWalletOption

KWalletAppID sets the KWallet application id.

func KWalletFolder

func KWalletFolder(folder string) KWalletOption

KWalletFolder sets the KWallet folder.

type KeyCtlOption

type KeyCtlOption func(*keyCtlConfig)

KeyCtlOption configures the built-in Linux keyctl provider.

func KeyCtlPerm

func KeyCtlPerm(perm uint32) KeyCtlOption

KeyCtlPerm sets the Linux kernel keyring permission mask.

func KeyCtlScope

func KeyCtlScope(scope string) KeyCtlOption

KeyCtlScope sets the Linux kernel keyring scope.

type KeychainOption

type KeychainOption func(*keychainConfig)

KeychainOption configures the built-in macOS Keychain provider.

func KeychainAccessibleWhenUnlocked

func KeychainAccessibleWhenUnlocked(enabled bool) KeychainOption

KeychainAccessibleWhenUnlocked controls whether items are accessible only while the device is unlocked.

func KeychainName

func KeychainName(name string) KeychainOption

KeychainName sets the macOS keychain name.

func KeychainPrompt

func KeychainPrompt(prompt PromptFunc) KeychainOption

KeychainPrompt sets the macOS keychain password prompt.

func KeychainSynchronizable

func KeychainSynchronizable(enabled bool) KeychainOption

KeychainSynchronizable controls whether created items can synchronize to iCloud.

func KeychainTrustApplication

func KeychainTrustApplication(enabled bool) KeychainOption

KeychainTrustApplication controls whether created items trust the calling application by default.

type Keyring

type Keyring interface {
	Get(context.Context, string) (Item, error)
	Set(context.Context, Item) error
	Remove(context.Context, string) error
	Keys(context.Context) ([]string, error)
}

Keyring provides the common credential storage interface. Keyrings that own external resources may also implement io.Closer.

func Open

func Open(ctx context.Context, opts ...Option) (Keyring, error)

Open opens the first configured backend that is available.

Example
package main

import (
	"context"
	"log"

	"github.com/lox/keyring"
)

func main() {
	ctx := context.Background()

	// Use the best keyring implementation for your operating system
	kr, err := keyring.Open(ctx, keyring.WithServiceName("my-service"))
	if err != nil {
		log.Fatal(err)
	}

	v, err := kr.Get(ctx, "llamas")
	if err != nil {
		log.Fatal(err)
	}

	log.Printf("llamas was %v", v)
}

type Metadata

type Metadata struct {
	*Item
	ModificationTime time.Time
}

Metadata is the non-secret data for a stored credential. Retrieving metadata must not require authentication. The embedded Item should be filled in with an empty Data field. Item may be nil when the backend can only return timestamps.

type MetadataReader

type MetadataReader interface {
	Metadata(context.Context, string) (Metadata, error)
}

MetadataReader is implemented by keyrings that can read metadata without exposing secret data.

type OpenOptions

type OpenOptions struct {
	ServiceName string
}

OpenOptions are the provider-visible options selected by Open.

type Option

type Option func(*options) error

Option configures Open.

func WithBackends

func WithBackends(backends ...Backend) Option

WithBackends sets the backend order to try. If unset, Open tries available providers in default order.

func WithFallbackPolicy

func WithFallbackPolicy(policy FallbackPolicy) Option

WithFallbackPolicy controls when Open tries the next provider after an open error.

func WithProvider

func WithProvider(provider Provider) Option

WithProvider adds or replaces one provider.

func WithProviders

func WithProviders(providers ...Provider) Option

WithProviders adds or replaces providers. A provider with the same backend as an existing provider replaces it for this Open call.

func WithServiceName

func WithServiceName(name string) Option

WithServiceName sets the service name used by providers that group items by application or service.

type PassOption

type PassOption func(*passConfig)

PassOption configures the built-in pass provider.

func PassCmd

func PassCmd(cmd string) PassOption

PassCmd sets the pass executable name.

func PassDir

func PassDir(dir string) PassOption

PassDir sets the password-store directory.

func PassPrefix

func PassPrefix(prefix string) PassOption

PassPrefix sets the item path prefix for pass.

type PromptFunc

type PromptFunc func(string) (string, error)

PromptFunc is a function used to prompt the user for a password.

func FixedStringPrompt

func FixedStringPrompt(value string) PromptFunc

FixedStringPrompt returns a prompt function that always returns value.

type Provider

type Provider struct {
	Backend Backend
	Open    func(context.Context, OpenOptions) (Keyring, error)
}

Provider describes a backend implementation.

func DefaultProviders

func DefaultProviders() []Provider

DefaultProviders returns the built-in backend providers.

func FileProvider

func FileProvider(opts ...FileOption) Provider

FileProvider returns the built-in encrypted file provider.

func KWalletProvider

func KWalletProvider(opts ...KWalletOption) Provider

KWalletProvider returns the built-in KWallet provider.

func KeyCtlProvider

func KeyCtlProvider(opts ...KeyCtlOption) Provider

KeyCtlProvider returns the built-in Linux keyctl provider.

func KeychainProvider

func KeychainProvider(opts ...KeychainOption) Provider

KeychainProvider returns the built-in macOS Keychain provider.

func PassProvider

func PassProvider(opts ...PassOption) Provider

PassProvider returns the built-in pass provider.

func SecretServiceProvider

func SecretServiceProvider(opts ...SecretServiceOption) Provider

SecretServiceProvider returns the built-in Secret Service provider.

func WinCredProvider

func WinCredProvider(opts ...WinCredOption) Provider

WinCredProvider returns the built-in Windows Credential Manager provider.

type SecretServiceOption

type SecretServiceOption func(*secretServiceConfig)

SecretServiceOption configures the built-in Secret Service provider.

func SecretServiceCollection

func SecretServiceCollection(name string) SecretServiceOption

SecretServiceCollection sets the Secret Service collection name.

type WinCredOption

type WinCredOption func(*winCredConfig)

WinCredOption configures the built-in Windows Credential Manager provider.

func WinCredPrefix

func WinCredPrefix(prefix string) WinCredOption

WinCredPrefix sets the key prefix used by Windows Credential Manager.

Directories

Path Synopsis
cmd
keyring command
Command keyring provides a small manual testing CLI for the keyring package.
Command keyring provides a small manual testing CLI for the keyring package.

Jump to

Keyboard shortcuts

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